1dnl ----------------------------------------------------------------
2dnl Tests for various C++11 features.  These will probably only work
3dnl if they are run after the autoconf test that sets -std=c++11.
4dnl ----------------------------------------------------------------
5
6dnl Test C++11 std::isnan, std::isinf
7AC_DEFUN([LIBMESH_TEST_CXX11_ISNAN_ISINF],
8  [
9    have_cxx11_isnan=no
10    have_cxx11_isinf=no
11
12    AC_LANG_PUSH([C++])
13
14    old_CXXFLAGS="$CXXFLAGS"
15    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
16
17    AC_MSG_CHECKING(for C++11 std::isnan)
18    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
19    @%:@include <cmath>
20    ]], [[
21    if (std::isnan(0.0))
22      return 1;
23    ]])],[
24        AC_MSG_RESULT(yes)
25        have_cxx11_isnan=yes
26        dnl AC_DEFINE(HAVE_CXX11_ISNAN, 1, [Flag indicating whether compiler supports std::isnan])
27    ],[
28        AC_MSG_RESULT(no)
29    ])
30
31    AC_MSG_CHECKING(for C++11 std::isinf)
32    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
33    @%:@include <cmath>
34    ]], [[
35    if (std::isinf(0.0))
36      return 1;
37    ]])],[
38        AC_MSG_RESULT(yes)
39        have_cxx11_isinf=yes
40        dnl AC_DEFINE(HAVE_CXX11_ISINF, 1, [Flag indicating whether compiler supports std::isinf])
41    ],[
42        AC_MSG_RESULT(no)
43    ])
44
45    dnl Reset the flags
46    CXXFLAGS="$old_CXXFLAGS"
47    AC_LANG_POP([C++])
48  ])
49
50dnl Test C++11 std::array
51AC_DEFUN([LIBMESH_TEST_CXX11_ARRAY],
52  [
53    have_cxx11_array=no
54
55    AC_MSG_CHECKING(for C++11 std::array)
56    AC_LANG_PUSH([C++])
57
58    old_CXXFLAGS="$CXXFLAGS"
59    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
60
61    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
62    @%:@include <array>
63    ]], [[
64    std::array<double, 4> a;
65    a[0] = 42.0;
66    double * begin = a.data();
67    ]])],[
68        AC_MSG_RESULT(yes)
69        have_cxx11_array=yes
70    ],[
71        AC_MSG_RESULT(no)
72    ])
73
74    dnl Reset the flags
75    CXXFLAGS="$old_CXXFLAGS"
76    AC_LANG_POP([C++])
77  ])
78
79dnl Test C++11 std::vector::data()
80AC_DEFUN([LIBMESH_TEST_CXX11_VECTOR_DATA],
81  [
82    have_cxx11_vector_data=no
83
84    AC_MSG_CHECKING(for C++11 std::vector::data() API)
85    AC_LANG_PUSH([C++])
86
87    old_CXXFLAGS="$CXXFLAGS"
88    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
89
90    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
91    @%:@include <vector>
92    ]], [[
93    std::vector<int> v(10);
94    int * begin = v.data();
95    ]])],[
96        AC_MSG_RESULT(yes)
97        have_cxx11_vector_data=yes
98    ],[
99        AC_MSG_RESULT(no)
100    ])
101
102    dnl Reset the flags
103    CXXFLAGS="$old_CXXFLAGS"
104    AC_LANG_POP([C++])
105  ])
106
107dnl Test C++11 std::iota
108AC_DEFUN([LIBMESH_TEST_CXX11_IOTA],
109  [
110    have_cxx11_iota=no
111
112    AC_MSG_CHECKING(for C++11 std::iota algorithm)
113    AC_LANG_PUSH([C++])
114
115    old_CXXFLAGS="$CXXFLAGS"
116    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
117
118    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
119    @%:@include <vector>
120    @%:@include <numeric>
121    ]], [[
122    std::vector<int> v(10);
123    std::iota(v.begin(), v.end(), 0);
124    ]])],[
125        AC_MSG_RESULT(yes)
126        have_cxx11_iota=yes
127    ],[
128        AC_MSG_RESULT(no)
129    ])
130
131    dnl Reset the flags
132    CXXFLAGS="$old_CXXFLAGS"
133    AC_LANG_POP([C++])
134  ])
135
136dnl Test C++11 std::map,set,multimap,multiset iterator-returning erase() APIs.
137AC_DEFUN([LIBMESH_TEST_CXX11_CONTAINER_ERASE],
138  [
139    have_cxx11_container_erase=no
140
141    AC_MSG_CHECKING(for C++11 std container erase() functions returning iterators)
142    AC_LANG_PUSH([C++])
143
144    old_CXXFLAGS="$CXXFLAGS"
145    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
146
147    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
148    @%:@include <map>
149    @%:@include <set>
150    ]], [[
151    {
152      std::map<int, int> m;
153      m.insert(std::make_pair(1,2));
154      std::map<int, int>::iterator it = m.erase(m.begin());
155    }
156    {
157      std::set<int> s;
158      s.insert(1);
159      std::set<int>::iterator it = s.erase(s.begin());
160    }
161    {
162      std::multimap<int, int> m;
163      m.insert(std::make_pair(1,2));
164      std::multimap<int, int>::iterator it = m.erase(m.begin());
165    }
166    {
167      std::multiset<int> s;
168      s.insert(1);
169      std::multiset<int>::iterator it = s.erase(s.begin());
170    }
171    ]])],[
172        AC_MSG_RESULT(yes)
173        have_cxx11_container_erase=yes
174    ],[
175        AC_MSG_RESULT(no)
176    ])
177
178    dnl Reset the flags
179    CXXFLAGS="$old_CXXFLAGS"
180    AC_LANG_POP([C++])
181  ])
182
183dnl Test C++11 std::map,set,multimap,multiset emplace APIs.
184AC_DEFUN([LIBMESH_TEST_CXX11_CONTAINER_EMPLACE],
185  [
186    have_cxx11_container_emplace=no
187
188    AC_MSG_CHECKING(for C++11 std container emplace() functions)
189    AC_LANG_PUSH([C++])
190
191    old_CXXFLAGS="$CXXFLAGS"
192    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
193
194    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
195    @%:@include <map>
196    @%:@include <set>
197    @%:@include <vector>
198    ]], [[
199    {
200      std::map<int, int> m;
201      m.emplace(1,2);
202      m.emplace_hint(m.begin(), 0, 3);
203    }
204    {
205      std::set<int> s;
206      s.emplace(1);
207      s.emplace_hint(s.begin(), 0);
208    }
209    {
210      std::multimap<int, int> m;
211      m.emplace(1,2);
212      m.emplace_hint(m.begin(), 0, 3);
213    }
214    {
215      std::multiset<int> s;
216      s.emplace(1);
217      s.emplace_hint(s.begin(), 0);
218    }
219    {
220      std::vector<int> v;
221      v.emplace(v.begin(), 0);
222      v.emplace_back(1);
223    }
224    ]])],[
225        AC_MSG_RESULT(yes)
226        have_cxx11_container_emplace=yes
227    ],[
228        AC_MSG_RESULT(no)
229    ])
230
231    dnl Reset the flags
232    CXXFLAGS="$old_CXXFLAGS"
233    AC_LANG_POP([C++])
234  ])
235
236dnl Test C++11 std::tuple and several related helper functions.
237AC_DEFUN([LIBMESH_TEST_CXX11_BEGIN_END],
238  [
239    have_cxx11_begin_end=no
240
241    AC_MSG_CHECKING(for C++11 std::begin/end support for arrays)
242    AC_LANG_PUSH([C++])
243
244    dnl For this and all of the C++ standards tests: Save the original
245    dnl CXXFLAGS (if any) before appending the $switch determined by
246    dnl AX_CXX_COMPILE_STDCXX_11, and any compiler flags specified by
247    dnl the user in the libmesh_CXXFLAGS environment variable, letting
248    dnl that override everything else.
249    old_CXXFLAGS="$CXXFLAGS"
250    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
251
252    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
253    @%:@include <iterator>
254    @%:@include <algorithm>
255    ]], [[
256    int array[5] = {3, 1, 5, 2, 4};
257    std::sort(std::begin(array), std::end(array));
258    ]])],[
259        AC_MSG_RESULT(yes)
260        have_cxx11_begin_end=yes
261    ],[
262        AC_MSG_RESULT(no)
263    ])
264
265    dnl Reset the flags
266    CXXFLAGS="$old_CXXFLAGS"
267    AC_LANG_POP([C++])
268  ])
269
270dnl Test C++11 std::tuple and several related helper functions.
271AC_DEFUN([LIBMESH_TEST_CXX11_TUPLE],
272  [
273    have_cxx11_tuple=no
274
275    AC_MSG_CHECKING(for C++11 std::tuple support)
276    AC_LANG_PUSH([C++])
277
278    dnl For this and all of the C++ standards tests: Save the original
279    dnl CXXFLAGS (if any) before appending the $switch determined by
280    dnl AX_CXX_COMPILE_STDCXX_11, and any compiler flags specified by
281    dnl the user in the libmesh_CXXFLAGS environment variable, letting
282    dnl that override everything else.
283    old_CXXFLAGS="$CXXFLAGS"
284    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
285
286    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
287    @%:@include <tuple>
288    @%:@include <map>
289    @%:@include <string>
290    ]], [[
291    // Test std::make_tuple
292    std::map<int, std::tuple<double, char, std::string>> students;
293    students[0] = std::make_tuple(3.8, 'A', "Lisa Simpson");
294    students[1] = std::make_tuple(2.9, 'C', "Milhouse Van Houten");
295
296    // Test templated std::get() method.
297    std::get<0>(students[0]);
298    std::get<1>(students[0]);
299    std::get<2>(students[0]);
300
301    // Test std::tie and std::ignore which are declared in the <tuple> header.
302    double gpa1;
303    std::string name1;
304    std::tie(gpa1, std::ignore, name1) = students[1];
305
306    // Test std::tuple_cat(), which combines together one or more
307    // objects, not necessarily tuples, into a single tuple.
308    auto t = std::tuple_cat(students[0], students[1], std::make_pair("foo", 42));
309    ]])],[
310        AC_MSG_RESULT(yes)
311        AC_DEFINE(HAVE_CXX11_TUPLE, 1, [Flag indicating whether compiler supports std::move])
312        have_cxx11_tuple=yes
313    ],[
314        AC_MSG_RESULT(no)
315    ])
316
317    dnl Reset the flags
318    CXXFLAGS="$old_CXXFLAGS"
319    AC_LANG_POP([C++])
320
321    AM_CONDITIONAL(HAVE_CXX11_TUPLE, test x$have_cxx11_tuple == xyes)
322  ])
323
324dnl Test C++11 fixed type enumerations.
325AC_DEFUN([LIBMESH_TEST_CXX11_FIXED_TYPE_ENUM],
326  [
327    have_cxx11_fixed_type_enum=no
328
329    AC_MSG_CHECKING(for C++11 fixed type enumeration support)
330    AC_LANG_PUSH([C++])
331
332    dnl For this and all of the C++ standards tests: Save the original
333    dnl CXXFLAGS (if any) before appending the $switch determined by
334    dnl AX_CXX_COMPILE_STDCXX_11, and any compiler flags specified by
335    dnl the user in the libmesh_CXXFLAGS environment variable, letting
336    dnl that override everything else.
337    old_CXXFLAGS="$CXXFLAGS"
338    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
339
340    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
341    enum Fruit : int {APPLE=0, ORANGE=1};
342    ]], [[
343    Fruit f = APPLE;
344    ]])],[
345        AC_MSG_RESULT(yes)
346        AC_DEFINE(HAVE_CXX11_FIXED_TYPE_ENUM, 1, [Flag indicating whether compiler supports fixed type enumerations])
347        have_cxx11_fixed_type_enum=yes
348    ],[
349        AC_MSG_RESULT(no)
350    ])
351
352    dnl Reset the flags
353    CXXFLAGS="$old_CXXFLAGS"
354    AC_LANG_POP([C++])
355
356    AM_CONDITIONAL(HAVE_CXX11_FIXED_TYPE_ENUM, test x$have_cxx11_fixed_type_enum == xyes)
357  ])
358
359dnl Test C++11 fixed type enumeration forward declarations.
360AC_DEFUN([LIBMESH_TEST_CXX11_FIXED_TYPE_ENUM_FWD],
361  [
362    have_cxx11_fixed_type_enum_fwd=no
363
364    AC_MSG_CHECKING(for C++11 fixed type enumeration forward declaration support)
365    AC_LANG_PUSH([C++])
366
367    old_CXXFLAGS="$CXXFLAGS"
368    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
369
370    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
371    @%:@include <iostream>
372    enum Foo : int;
373    void func(Foo f) { std::cout << f << std::endl; }
374    enum Foo : int { FOO0 = 0, FOO1 = 1, FOO2 = 2 };
375    ]], [[
376    func(FOO0);
377    func(FOO1);
378    func(FOO2);
379    ]])],[
380        AC_MSG_RESULT(yes)
381        AC_DEFINE(HAVE_CXX11_FIXED_TYPE_ENUM_FWD, 1, [Flag indicating whether compiler supports fixed type enumerations])
382        have_cxx11_fixed_type_enum_fwd=yes
383    ],[
384        AC_MSG_RESULT(no)
385    ])
386
387    dnl Reset the flags
388    CXXFLAGS="$old_CXXFLAGS"
389    AC_LANG_POP([C++])
390
391    AM_CONDITIONAL(HAVE_CXX11_FIXED_TYPE_ENUM_FWD, test x$have_cxx11_fixed_type_enum_fwd == xyes)
392  ])
393
394dnl Properly implemented move constructors require rvalue references,
395dnl std::move, and noexcept, so this tests for all of those features.
396AC_DEFUN([LIBMESH_TEST_CXX11_MOVE_CONSTRUCTORS],
397  [
398    have_cxx11_move_constructors=no
399
400    AC_MSG_CHECKING(for C++11 move constructor support)
401    AC_LANG_PUSH([C++])
402
403    old_CXXFLAGS="$CXXFLAGS"
404    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
405
406    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
407    @%:@include <utility>
408    class move_constructable_base
409    {
410    public:
411      move_constructable_base() {}
412      move_constructable_base(move_constructable_base && other) noexcept {}
413    };
414    class move_constructable : public move_constructable_base
415    {
416    public:
417      move_constructable() {}
418      move_constructable(move_constructable && other) noexcept : move_constructable_base(std::move(other)) {}
419    };
420    ]], [[
421        move_constructable m1;
422        move_constructable m2(std::move(m1));
423    ]])],[
424        AC_MSG_RESULT(yes)
425        AC_DEFINE(HAVE_CXX11_MOVE_CONSTRUCTORS, 1, [Flag indicating whether compiler supports move construction])
426        have_cxx11_move_constructors=yes
427    ],[
428        AC_MSG_RESULT(no)
429    ])
430
431    # Reset the flags
432    CXXFLAGS="$old_CXXFLAGS"
433    AC_LANG_POP([C++])
434
435    AM_CONDITIONAL(HAVE_CXX11_MOVE_CONSTRUCTORS, test x$have_cxx11_move_constructors == xyes)
436  ])
437
438
439AC_DEFUN([LIBMESH_TEST_CXX11_RANGEFOR],
440  [
441    have_cxx11_rangefor=no
442
443    AC_MSG_CHECKING(for C++11 range-based for loop support)
444    AC_LANG_PUSH([C++])
445
446    old_CXXFLAGS="$CXXFLAGS"
447    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
448
449    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
450        @%:@include <iostream>
451        @%:@include <vector>
452        void print(const std::vector<int> & v)
453        {
454          for (const int & x : v)
455            std::cout << x << ' ';
456          std::cout << std::endl;
457        }
458    ]], [[
459        std::vector<int> v(3);
460        print(v);
461    ]])],[
462        AC_MSG_RESULT(yes)
463        AC_DEFINE(HAVE_CXX11_RANGEFOR, 1, [Flag indicating whether compiler supports range-based for loops])
464        have_cxx11_rangefor=yes
465    ],[
466        AC_MSG_RESULT(no)
467    ])
468
469    # Reset the flags
470    CXXFLAGS="$old_CXXFLAGS"
471    AC_LANG_POP([C++])
472
473    AM_CONDITIONAL(HAVE_CXX11_RANGEFOR, test x$have_cxx11_rangefor == xyes)
474  ])
475
476
477AC_DEFUN([LIBMESH_TEST_CXX11_DECLTYPE],
478  [
479    have_cxx11_decltype=no
480
481    AC_MSG_CHECKING(for C++11 decltype support)
482    AC_LANG_PUSH([C++])
483
484    old_CXXFLAGS="$CXXFLAGS"
485    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
486
487    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
488        @%:@include <vector>
489    ]], [[
490        int a;
491        decltype(a) b;
492        std::vector<int> vec(10);
493        for (auto i = decltype(vec.size())(0); i < vec.size(); ++i)
494          vec[i] += i;
495    ]])],[
496        AC_MSG_RESULT(yes)
497        AC_DEFINE(HAVE_CXX11_DECLTYPE, 1, [Flag indicating whether compiler supports decltype])
498        have_cxx11_decltype=yes
499    ],[
500        AC_MSG_RESULT(no)
501    ])
502
503    # Reset the flags
504    CXXFLAGS="$old_CXXFLAGS"
505    AC_LANG_POP([C++])
506
507    AM_CONDITIONAL(HAVE_CXX11_DECLTYPE, test x$have_cxx11_decltype == xyes)
508  ])
509
510
511AC_DEFUN([LIBMESH_TEST_CXX11_RVALUE_REFERENCES],
512  [
513    have_cxx11_rvalue_references=no
514
515    AC_MSG_CHECKING(for C++11 rvalue references support)
516    AC_LANG_PUSH([C++])
517
518    old_CXXFLAGS="$CXXFLAGS"
519    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
520
521    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
522      int foo(int && x) { return x; }
523      int bar() { return 4; }
524    ]], [[
525      // Call function that takes an rvalue reference.
526      foo (bar());
527    ]])],[
528        AC_MSG_RESULT(yes)
529        AC_DEFINE(HAVE_CXX11_RVALUE_REFERENCES, 1, [Flag indicating whether compiler supports rvalue references])
530        have_cxx11_rvalue_references=yes
531    ],[
532        AC_MSG_RESULT(no)
533    ])
534
535    # Reset the flags
536    CXXFLAGS="$old_CXXFLAGS"
537    AC_LANG_POP([C++])
538
539    AM_CONDITIONAL(HAVE_CXX11_RVALUE_REFERENCES, test x$have_cxx11_rvalue_references == xyes)
540  ])
541
542
543AC_DEFUN([LIBMESH_TEST_CXX11_AUTO],
544  [
545    have_cxx11_auto=no
546
547    AC_MSG_CHECKING(for C++11 auto keyword support)
548    AC_LANG_PUSH([C++])
549
550    old_CXXFLAGS="$CXXFLAGS"
551    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
552
553    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
554    ]], [[
555      int x = 5;
556      auto y = x;
557    ]])],[
558        AC_MSG_RESULT(yes)
559        AC_DEFINE(HAVE_CXX11_AUTO, 1, [Flag indicating whether compiler supports the auto keyword])
560        have_cxx11_auto=yes
561    ],[
562        AC_MSG_RESULT(no)
563    ])
564
565    # Reset the flags
566    CXXFLAGS="$old_CXXFLAGS"
567    AC_LANG_POP([C++])
568
569    AM_CONDITIONAL(HAVE_CXX11_AUTO, test x$have_cxx11_auto == xyes)
570  ])
571
572
573AC_DEFUN([LIBMESH_TEST_CXX11_LAMBDA],
574  [
575    have_cxx11_lambda=no
576
577    AC_MSG_CHECKING(for C++11 lambda support)
578    AC_LANG_PUSH([C++])
579
580    old_CXXFLAGS="$CXXFLAGS"
581    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
582
583    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
584      // typedef for a function pointer that takes int and returns bool.
585      typedef bool (*FunctionPointer) (int);
586
587      // A function that takes a pointer to a function that takes an int,
588      // calls it with the number 4, and returns the result.
589      bool f(FunctionPointer g) { return g(4); }
590    ]], [[
591      // Call f, passing it a lambda constructed on the fly instead
592      // of a standard function pointer.  The result should be true.
593      f ( [](int x) { return x > 3; } );
594    ]])],[
595        AC_MSG_RESULT(yes)
596        AC_DEFINE(HAVE_CXX11_LAMBDA, 1, [Flag indicating whether compiler supports lambdas])
597        have_cxx11_lambda=yes
598    ],[
599        AC_MSG_RESULT(no)
600    ])
601
602    # Reset the flags
603    CXXFLAGS="$old_CXXFLAGS"
604    AC_LANG_POP([C++])
605
606    AM_CONDITIONAL(HAVE_CXX11_LAMBDA, test x$have_cxx11_lambda == xyes)
607  ])
608
609
610AC_DEFUN([LIBMESH_TEST_CXX11_CONSTEXPR],
611  [
612    have_cxx11_constexpr=no
613
614    AC_MSG_CHECKING(for C++11 constexpr support)
615    AC_LANG_PUSH([C++])
616
617    old_CXXFLAGS="$CXXFLAGS"
618    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
619
620    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
621      constexpr int multiply (int x, int y) { return x * y; }
622    ]], [[
623      // The compiler should compute "val" at compile time.
624      const int val = multiply(10, 10);
625    ]])],[
626        AC_MSG_RESULT(yes)
627        AC_DEFINE(HAVE_CXX11_CONSTEXPR, 1, [Flag indicating whether compiler supports constexpr])
628        have_cxx11_constexpr=yes
629    ],[
630        AC_MSG_RESULT(no)
631    ])
632
633    # Reset the flags
634    CXXFLAGS="$old_CXXFLAGS"
635    AC_LANG_POP([C++])
636
637    AM_CONDITIONAL(HAVE_CXX11_CONSTEXPR, test x$have_cxx11_constexpr == xyes)
638  ])
639
640
641AC_DEFUN([LIBMESH_TEST_CXX11_ALIAS_DECLARATIONS],
642  [
643    have_cxx11_alias_declarations=no
644
645    AC_MSG_CHECKING(for C++11 alias declarations support)
646    AC_LANG_PUSH([C++])
647
648    old_CXXFLAGS="$CXXFLAGS"
649    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
650
651    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
652      template <typename T>
653      struct check
654      {
655        T t;
656      };
657
658      // An alias declaration is like a templated typedef
659      template <typename T>
660      using MyCheck = check<T>;
661    ]], [[
662      MyCheck<int> mc;
663    ]])],[
664        AC_MSG_RESULT(yes)
665        AC_DEFINE(HAVE_CXX11_ALIAS_DECLARATIONS, 1, [Flag indicating whether compiler supports alias declarations])
666        have_cxx11_alias_declarations=yes
667    ],[
668        AC_MSG_RESULT(no)
669    ])
670
671    # Reset the flags
672    CXXFLAGS="$old_CXXFLAGS"
673    AC_LANG_POP([C++])
674
675    AM_CONDITIONAL(HAVE_CXX11_ALIAS_DECLARATIONS, test x$have_cxx11_alias_declarations == xyes)
676  ])
677
678
679AC_DEFUN([LIBMESH_TEST_CXX11_SHARED_PTR],
680  [
681    have_cxx11_shared_ptr=no
682
683    AC_MSG_CHECKING(for C++11 std::shared_ptr support)
684    AC_LANG_PUSH([C++])
685
686    # Save any original value that CXXFLAGS had
687    old_CXXFLAGS="$CXXFLAGS"
688    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
689
690    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
691    @%:@include <memory>
692    ]], [[
693        std::shared_ptr<int> p1;
694        std::shared_ptr<int> p2 (new int);
695        std::shared_ptr<int> p3 (p2);
696        p3.reset(new int);
697        p3 = std::make_shared<int>(5);
698    ]])],[
699        have_cxx11_shared_ptr=yes
700        AC_MSG_RESULT(yes)
701    ],[
702        have_cxx11_shared_ptr=no
703        AC_MSG_RESULT(no)
704    ])
705
706    dnl Only set the header file variable if our flag was set to 'yes'.
707    AS_IF([test "x$have_cxx11_shared_ptr" = "xyes"],
708          [AC_DEFINE(HAVE_CXX11_SHARED_PTR, 1, [Flag indicating whether compiler supports std::shared_ptr])])
709
710    # Reset the flags
711    CXXFLAGS="$old_CXXFLAGS"
712    AC_LANG_POP([C++])
713
714    AM_CONDITIONAL(HAVE_CXX11_SHARED_PTR, test x$have_cxx11_shared_ptr == xyes)
715  ])
716
717
718AC_DEFUN([LIBMESH_TEST_CXX11_UNIQUE_PTR],
719  [
720    have_cxx11_unique_ptr=no
721
722    AC_MSG_CHECKING(for C++11 std::unique_ptr support)
723    AC_LANG_PUSH([C++])
724
725    old_CXXFLAGS="$CXXFLAGS"
726    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
727
728    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
729    @%:@include <iostream>
730    @%:@include <memory>
731    struct Foo
732    {
733      Foo()      { std::cout << "Foo::Foo\n";  }
734      ~Foo()     { std::cout << "Foo::~Foo\n"; }
735    };
736        ]], [[
737    {
738      // up now owns a Foo
739      std::unique_ptr<Foo> up(new Foo);
740    } // Foo deleted when up goes out of scope
741    ]])],[
742        AC_MSG_RESULT(yes)
743        AC_DEFINE(HAVE_CXX11_UNIQUE_PTR, 1, [Flag indicating whether compiler supports std::unique_ptr])
744        have_cxx11_unique_ptr=yes
745    ],[
746      AC_MSG_RESULT(no)
747    ])
748
749    # Reset the flags
750    CXXFLAGS="$old_CXXFLAGS"
751    AC_LANG_POP([C++])
752
753    AM_CONDITIONAL(HAVE_CXX11_UNIQUE_PTR, test x$have_cxx11_unique_ptr == xyes)
754  ])
755
756
757AC_DEFUN([LIBMESH_TEST_CXX14_MAKE_UNIQUE],
758  [
759    have_cxx14_make_unique=no
760
761    # std::make_unique is actually part of the C++14 standard, but some
762    # compilers might (?) support it via the -std=c++11 flag, or eventually
763    # with no flag at all.
764    AC_MSG_CHECKING(for C++14 std::make_unique support)
765    AC_LANG_PUSH([C++])
766
767    old_CXXFLAGS="$CXXFLAGS"
768    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
769
770    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
771    @%:@include <memory>
772        ]], [[
773    {
774      // Normally, you would use "auto" on the LHS here to avoid
775      // repeating the type name, but we are not testing auto here.
776      std::unique_ptr<int> up = std::make_unique<int>(42);
777    } // Foo deleted when up goes out of scope
778    ]])],[
779        AC_MSG_RESULT(yes)
780        AC_DEFINE(HAVE_CXX14_MAKE_UNIQUE, 1, [Flag indicating whether compiler supports std::make_unique])
781        have_cxx14_make_unique=yes
782    ],[
783      AC_MSG_RESULT(no)
784    ])
785
786    # Reset the flags
787    CXXFLAGS="$old_CXXFLAGS"
788    AC_LANG_POP([C++])
789
790    AM_CONDITIONAL(HAVE_CXX14_MAKE_UNIQUE, test x$have_cxx14_make_unique == xyes)
791  ])
792
793
794AC_DEFUN([LIBMESH_TEST_CXX11_MAKE_UNIQUE_WORKAROUND],
795  [
796    have_cxx11_make_unique_workaround=no
797
798    # This is a simple workaround for no std::make_unique in C++11:
799    # http://stackoverflow.com/questions/7038357/make-unique-and-perfect-forwarding
800    # Requires working rvalue references, std::forward, variadic
801    # templates, and std::unique_ptr from C++11.
802    AC_MSG_CHECKING(for C++11 std::make_unique workaround support)
803    AC_LANG_PUSH([C++])
804
805    old_CXXFLAGS="$CXXFLAGS"
806    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
807
808    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
809    @%:@include <memory>
810    namespace local
811    {
812      template<typename T, typename... Args>
813      std::unique_ptr<T> make_unique(Args&&... args)
814      {
815        return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
816      }
817    }
818        ]], [[
819    {
820      // Normally, you would use "auto" on the LHS here to avoid
821      // repeating the type name, but we are not testing auto here.
822      std::unique_ptr<int> up = local::make_unique<int>(42);
823    } // Foo deleted when up goes out of scope
824    ]])],[
825        AC_MSG_RESULT(yes)
826        AC_DEFINE(HAVE_CXX11_MAKE_UNIQUE_WORKAROUND, 1, [Flag indicating whether compiler supports C++11 std::make_unique workaround])
827        have_cxx11_make_unique_workaround=yes
828    ],[
829      AC_MSG_RESULT(no)
830    ])
831
832    # Reset the flags
833    CXXFLAGS="$old_CXXFLAGS"
834    AC_LANG_POP([C++])
835
836    AM_CONDITIONAL(HAVE_CXX11_MAKE_UNIQUE_WORKAROUND, test x$have_cxx11_make_unique_workaround == xyes)
837  ])
838
839
840
841
842AC_DEFUN([LIBMESH_TEST_CXX11_REGEX],
843  [
844    have_cxx11_regex=no
845
846    AC_MSG_CHECKING(for C++11 std::regex support)
847    AC_LANG_PUSH([C++])
848
849    old_CXXFLAGS="$CXXFLAGS"
850    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
851
852    dnl We actually have to try and *run* the test program, since
853    dnl GCC up to 4.8 will compile this but then is not able to run it.
854    dnl GCC 4.9.1 and Clang 3.5 are actually able to run this test code.
855    dnl
856    dnl Note the quadruple backslash below -- this is needed so it
857    dnl expands to 2 backslashes in the test program generated by
858    dnl Autoconf...
859    AC_RUN_IFELSE([AC_LANG_PROGRAM([[
860    @%:@include <regex>
861    ]], [[
862      std::regex integer_regex("(\\\\+|-)?[[:digit:]]+");
863      std::regex_match("abc", integer_regex);
864      std::regex_match("123", integer_regex);
865    ]])],[
866        AC_MSG_RESULT(yes)
867        AC_DEFINE(HAVE_CXX11_REGEX, 1, [Flag indicating whether compiler supports std::regex])
868        have_cxx11_regex=yes
869    ],[
870      AC_MSG_RESULT(no)
871    ],[
872      dnl The test program is not run when cross-compiling, so you are supposed to
873      dnl provide a "pessimistic" action here.  We'll just assume the compiler does
874      dnl not support C++11 regexes in this case.
875      AC_MSG_RESULT(no)
876    ])
877
878    # Reset the flags
879    CXXFLAGS="$old_CXXFLAGS"
880    AC_LANG_POP([C++])
881
882    AM_CONDITIONAL(HAVE_CXX11_REGEX, test x$have_cxx11_regex == xyes)
883  ])
884
885
886AC_DEFUN([LIBMESH_TEST_CXX11_OVERRIDE],
887  [
888    have_cxx11_override=no
889
890    AC_MSG_CHECKING(for C++11 override keyword support)
891    AC_LANG_PUSH([C++])
892
893    old_CXXFLAGS="$CXXFLAGS"
894    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
895
896    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
897    ]], [[
898      struct Base {
899      virtual void f() {}
900      };
901      struct Child : public Base {
902      virtual void f() override {}
903      };
904    ]])],[
905        AC_MSG_RESULT(yes)
906        AC_DEFINE(HAVE_CXX11_OVERRIDE, 1, [Flag indicating whether compiler supports the override keyword])
907        have_cxx11_override=yes
908    ],[
909      AC_MSG_RESULT(no)
910    ])
911
912    # Reset the flags
913    CXXFLAGS="$old_CXXFLAGS"
914    AC_LANG_POP([C++])
915
916    AM_CONDITIONAL(HAVE_CXX11_OVERRIDE, test x$have_cxx11_override == xyes)
917  ])
918
919
920
921AC_DEFUN([LIBMESH_TEST_CXX11_INITIALIZER_LIST],
922  [
923    have_cxx11_initializer_list=no
924
925    AC_MSG_CHECKING(for C++11 initializer list support)
926    AC_LANG_PUSH([C++])
927
928    old_CXXFLAGS="$CXXFLAGS"
929    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
930
931    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
932      @%:@include <vector>
933      @%:@include <string>
934    ]], [[
935      std::vector<std::string> v = { "xyzzy", "plugh", "abracadabra" };
936    ]])],[
937        AC_MSG_RESULT(yes)
938        AC_DEFINE(HAVE_CXX11_INITIALIZER_LIST, 1, [Flag indicating whether compiler supports initializer lists])
939        have_cxx11_initializer_list=yes
940    ],[
941      AC_MSG_RESULT(no)
942    ])
943
944    # Reset the flags
945    CXXFLAGS="$old_CXXFLAGS"
946    AC_LANG_POP([C++])
947
948    AM_CONDITIONAL(HAVE_CXX11_INITIALIZER_LIST, test x$have_cxx11_initializer_list == xyes)
949  ])
950
951
952AC_DEFUN([LIBMESH_TEST_CXX11_VARIADIC_TEMPLATES],
953  [
954    have_cxx11_variadic_templates=no
955
956    AC_MSG_CHECKING(for C++11 variadic template support)
957    AC_LANG_PUSH([C++])
958
959    old_CXXFLAGS="$CXXFLAGS"
960    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
961
962    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
963      // Base case
964      template <typename T>
965      T sum(T t) { return t; }
966
967      // Compute sum of arbitrary number of passed parameters.
968      template <typename T, typename ...P>
969      T sum(T t, P ...p)
970      {
971        t += sum(p...);
972        return t;
973      }
974    ]], [[
975      sum(1, 2, 3, 4, 5);
976    ]])],[
977        AC_MSG_RESULT(yes)
978        AC_DEFINE(HAVE_CXX11_VARIADIC_TEMPLATES, 1, [Flag indicating whether compiler supports variadic templates])
979        have_cxx11_variadic_templates=yes
980    ],[
981      AC_MSG_RESULT(no)
982    ])
983
984    # Reset the flags
985    CXXFLAGS="$old_CXXFLAGS"
986    AC_LANG_POP([C++])
987
988    AM_CONDITIONAL(HAVE_CXX11_VARIADIC_TEMPLATES, test x$have_cxx11_variadic_templates == xyes)
989  ])
990
991
992AC_DEFUN([LIBMESH_TEST_CXX11_THREAD],
993  [
994    have_cxx11_thread=no
995
996    AC_MSG_CHECKING(for C++11 <thread> support)
997    AC_LANG_PUSH([C++])
998
999    old_CXXFLAGS="$CXXFLAGS"
1000    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
1001
1002    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
1003      @%:@include <thread>
1004      @%:@include <atomic>
1005      @%:@include <mutex>
1006      void my_thread_func() {}
1007    ]], [[
1008      thread_local int i;
1009      std::thread t(my_thread_func);
1010      t.join();
1011
1012      std::atomic<bool> ab1, ab2;
1013      ab1.store(true, std::memory_order_relaxed);
1014      ab2.store(false, std::memory_order_relaxed);
1015      ab1.exchange(ab2);
1016
1017      std::mutex m;
1018      std::lock_guard<std::mutex> lock(m);
1019
1020      std::atomic_thread_fence(std::memory_order_acquire);
1021      std::atomic_thread_fence(std::memory_order_release);
1022
1023      // We use this function in one of our unit tests now.
1024      unsigned int n_threads = std::thread::hardware_concurrency();
1025    ]])],[
1026        AC_MSG_RESULT(yes)
1027        AC_DEFINE(HAVE_CXX11_THREAD, 1, [Flag indicating whether compiler supports std::thread])
1028        have_cxx11_thread=yes
1029    ],[
1030      AC_MSG_RESULT(no)
1031    ])
1032
1033    # Reset the flags
1034    CXXFLAGS="$old_CXXFLAGS"
1035    AC_LANG_POP([C++])
1036
1037    AM_CONDITIONAL(HAVE_CXX11_THREAD, test x$have_cxx11_thread == xyes)
1038  ])
1039
1040
1041AC_DEFUN([LIBMESH_TEST_CXX11_CONDITION_VARIABLE],
1042  [
1043    have_cxx11_condition_variable=no
1044
1045    AC_MSG_CHECKING(for C++11 <condition_variable> support)
1046    AC_LANG_PUSH([C++])
1047
1048    old_CXXFLAGS="$CXXFLAGS"
1049    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
1050
1051    # Test code is from the accepted answer on:
1052    # http://stackoverflow.com/questions/16350473/why-do-i-need-stdcondition-variable
1053    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
1054      @%:@include <iostream>
1055      @%:@include <condition_variable>
1056      @%:@include <mutex>
1057      @%:@include <thread>
1058      @%:@include <chrono>
1059
1060      bool is_ready = false;
1061      std::mutex m;
1062      std::condition_variable cv;
1063
1064      void
1065      test()
1066      {
1067        std::this_thread::sleep_for(std::chrono::seconds(30));
1068        std::unique_lock<std::mutex> ulock(m);
1069        is_ready = true;
1070        cv.notify_one();
1071      }
1072    ]], [[
1073      std::thread t(test);
1074      std::unique_lock<std::mutex> ulock(m);
1075      while (!is_ready)
1076        {
1077          cv.wait(ulock);
1078          if (!is_ready)
1079            std::cout << "Spurious wake up!\n";
1080        }
1081      t.join();
1082    ]])],[
1083        AC_MSG_RESULT(yes)
1084        AC_DEFINE(HAVE_CXX11_CONDITION_VARIABLE, 1, [Flag indicating whether compiler supports std::condition_variable])
1085        have_cxx11_condition_variable=yes
1086    ],[
1087      AC_MSG_RESULT(no)
1088    ])
1089
1090    # Reset the flags
1091    CXXFLAGS="$old_CXXFLAGS"
1092    AC_LANG_POP([C++])
1093
1094    AM_CONDITIONAL(HAVE_CXX11_CONDITION_VARIABLE, test x$have_cxx11_condition_variable == xyes)
1095  ])
1096
1097
1098
1099AC_DEFUN([LIBMESH_TEST_CXX11_TYPE_TRAITS],
1100  [
1101    # This is designed to be an exhaustive test of the capabilities of
1102    # the <type_traits> header, as defined by the C++11 standard.  We
1103    # don't use all of these in libmesh, but we want application code
1104    # to be able to rely on the value of LIBMESH_HAVE_CXX11_TYPE_TRAITS.
1105    #
1106    # Not all compilers fully implement the header.  For example, GCC
1107    # 4.9.1 does not provide the is_trivially_copyable() function, but
1108    # it does provide support for other <type_traits> functions.
1109    #
1110    # See also:
1111    # http://en.cppreference.com/w/cpp/header/type_traits
1112    have_cxx11_type_traits=no
1113
1114    AC_MSG_CHECKING(for C++11 <type_traits> support)
1115    AC_LANG_PUSH([C++])
1116
1117    old_CXXFLAGS="$CXXFLAGS"
1118    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
1119
1120    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
1121      @%:@include <iostream>
1122      @%:@include <type_traits>
1123
1124      // std::enable_if - the return type of the function is only defined if
1125      // T is an integral type.  Therefore, it's a *compile* error if you
1126      // try to call it with a non-integral type.
1127      template <class T>
1128      typename std::enable_if<std::is_integral<T>::value, bool>::type
1129      is_odd (T i)
1130      {
1131        return static_cast<bool>(i%2);
1132      }
1133
1134      // std::underlying_type - names the underlying type of an enum
1135      enum e1 {};
1136
1137      // typedef (named fn_ptr) for a function that takes nothing and returns char.
1138      typedef char (*fn_ptr)();
1139    ]], [[
1140      std::cout << std::is_void<char>::value
1141        // << std::is_null_pointer<char>::value                  // C++14
1142                << std::is_integral<char>::value
1143                << std::is_floating_point<char>::value
1144                << std::is_array<char>::value
1145                << std::is_enum<char>::value
1146                << std::is_union<char>::value
1147                << std::is_class<char>::value
1148                << std::is_function<char>::value
1149                << std::is_pointer<char>::value
1150                << std::is_lvalue_reference<char>::value
1151                << std::is_rvalue_reference<char>::value
1152                << std::is_member_object_pointer<char>::value
1153                << std::is_fundamental<char>::value
1154                << std::is_arithmetic<char>::value
1155                << std::is_scalar<char>::value
1156                << std::is_object<char>::value
1157                << std::is_compound<char>::value
1158                << std::is_reference<char>::value
1159                << std::is_member_pointer<char>::value
1160                << std::is_const<char>::value
1161                << std::is_volatile<char>::value
1162                << std::is_trivial<char>::value
1163                << std::is_trivially_copyable<char>::value // Not supported by GCC 4.6.3 with -std=c++0x
1164                << std::is_standard_layout<char>::value
1165                << std::is_pod<char>::value
1166                << std::is_literal_type<char>::value
1167                << std::is_empty<char>::value
1168                << std::is_polymorphic<char>::value
1169                << std::is_abstract<char>::value
1170                << std::is_signed<char>::value
1171                << std::is_unsigned<char>::value
1172                << std::is_constructible<char>::value
1173                << std::is_trivially_constructible<char>::value
1174                << std::is_nothrow_constructible<char>::value
1175                << std::is_default_constructible<char>::value
1176                << std::is_trivially_default_constructible<char>::value
1177                << std::is_nothrow_default_constructible<char>::value
1178                << std::is_copy_constructible<char>::value
1179                << std::is_trivially_copy_constructible<char>::value
1180                << std::is_nothrow_copy_constructible<char>::value
1181                << std::is_move_constructible<char>::value
1182                << std::is_trivially_move_constructible<char>::value
1183                << std::is_nothrow_move_constructible<char>::value
1184                << std::is_assignable<char, char>::value
1185                << std::is_trivially_assignable<char, char>::value
1186                << std::is_nothrow_assignable<char, char>::value
1187                << std::is_copy_assignable<char>::value
1188                << std::is_trivially_copy_assignable<char>::value
1189                << std::is_nothrow_copy_assignable<char>::value
1190                << std::is_move_assignable<char>::value
1191                << std::is_trivially_move_assignable<char>::value
1192                << std::is_nothrow_move_assignable<char>::value
1193                << std::is_destructible<char>::value
1194                << std::is_trivially_destructible<char>::value
1195                << std::is_nothrow_destructible<char>::value
1196                << std::has_virtual_destructor<char>::value
1197                << std::alignment_of<char>::value
1198                << std::rank<char>::value
1199                << std::extent<char>::value
1200                << std::is_same<char, char>::value
1201                << std::is_base_of<char, char>::value
1202                << std::is_convertible<char, char>::value
1203                << std::is_same<char, std::remove_cv<const char>::type>::value // std::remove_cv
1204                << std::is_same<char, std::remove_const<const char>::type>::value // std::remove_const
1205                << std::is_same<char, std::remove_volatile<volatile char>::type>::value // std::remove_volatile
1206                << std::is_same<const volatile char, std::add_cv<char>::type>::value // std::add_cv
1207                << std::is_same<const char, std::add_const<char>::type>::value // std::add_const
1208                << std::is_same<volatile char, std::add_volatile<char>::type>::value // std::add_volatile
1209                << std::is_same<char, std::remove_reference<char &>::type>::value // std::remove_reference
1210                << std::is_same<char &, std::add_lvalue_reference<char>::type>::value // std::add_lvalue_reference
1211                << std::is_same<char &&, std::add_rvalue_reference<char>::type>::value // std::add_rvalue_reference
1212                << std::is_same<char, std::remove_pointer<char *>::type>::value // std::remove_pointer
1213                << std::is_same<char *, std::add_pointer<char>::type>::value // std::add_pointer
1214                << std::is_same<char, std::make_signed<unsigned char>::type>::value // std::make_signed
1215                << std::is_same<unsigned char, std::make_unsigned<char>::type>::value // std::make_unsigned
1216                << std::is_same<char, std::remove_extent<char>::type>::value // std::remove_extent
1217                << std::is_same<char, std::remove_all_extents<char>::type>::value // std::remove_all_extents
1218                << std::is_same<char, std::decay<const char &>::type>::value // std::decay
1219                << is_odd(13) // std::enable_if
1220                << std::is_same<char, std::conditional<true, /*type if true*/char, /*type if false*/int>::type>::value // std::conditional
1221                << std::is_same<long, std::common_type<char, short, int, long>::type>::value // std::common_type
1222                << std::is_same<int, std::underlying_type<e1>::type>::value // std::underlying_type
1223                << std::is_same<char, std::result_of<fn_ptr()>::type>::value // std::result_of
1224                << std::false_type::value
1225                << std::true_type::value
1226                << std::endl;
1227
1228      // std::aligned_storage
1229      typedef std::aligned_storage</*store objects of length=*/1>::type aligned_t;
1230
1231      // std::aligned_union
1232      typedef std::aligned_union</*size of at least*/32, int, char, double>::type union_t;
1233    ]])],[
1234        AC_MSG_RESULT(yes)
1235        AC_DEFINE(HAVE_CXX11_TYPE_TRAITS, 1, [Flag indicating whether compiler supports <type_traits>])
1236        have_cxx11_type_traits=yes
1237    ],[
1238      AC_MSG_RESULT(no)
1239    ])
1240
1241    # Reset the flags
1242    CXXFLAGS="$old_CXXFLAGS"
1243    AC_LANG_POP([C++])
1244
1245    AM_CONDITIONAL(HAVE_CXX11_TYPE_TRAITS, test x$have_cxx11_type_traits == xyes)
1246  ])
1247
1248
1249AC_DEFUN([LIBMESH_TEST_CXX11_MATH_FUNCS],
1250  [
1251    have_cxx11_inverse_hyperbolic_sine=no
1252    have_cxx11_inverse_hyperbolic_cosine=no
1253    have_cxx11_inverse_hyperbolic_tangent=no
1254
1255    have_cxx11_inverse_hyperbolic_sine_complex=no
1256    have_cxx11_inverse_hyperbolic_cosine_complex=no
1257    have_cxx11_inverse_hyperbolic_tangent_complex=no
1258
1259    AC_LANG_PUSH([C++])
1260
1261    old_CXXFLAGS="$CXXFLAGS"
1262    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
1263
1264    # Test for asinh
1265    AC_MSG_CHECKING(for C++11 std::asinh support in <cmath>)
1266    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
1267      @%:@include <cmath>
1268    ]], [[
1269      double x = std::asinh(1.);
1270    ]])],[
1271        AC_MSG_RESULT(yes)
1272        AC_DEFINE(HAVE_CXX11_INVERSE_HYPERBOLIC_SINE, 1, [Flag indicating whether compiler supports std::asinh])
1273        have_cxx11_inverse_hyperbolic_sine=yes
1274    ],[
1275      AC_MSG_RESULT(no)
1276    ])
1277
1278    # Test for acosh
1279    AC_MSG_CHECKING(for C++11 std::acosh support in <cmath>)
1280    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
1281      @%:@include <cmath>
1282    ]], [[
1283      double x = std::acosh(1.);
1284    ]])],[
1285        AC_MSG_RESULT(yes)
1286        AC_DEFINE(HAVE_CXX11_INVERSE_HYPERBOLIC_COSINE, 1, [Flag indicating whether compiler supports std::acosh])
1287        have_cxx11_inverse_hyperbolic_cosine=yes
1288    ],[
1289      AC_MSG_RESULT(no)
1290    ])
1291
1292    # Test for atanh
1293    AC_MSG_CHECKING(for C++11 std::atanh support in <cmath>)
1294    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
1295      @%:@include <cmath>
1296    ]], [[
1297      double x = std::atanh(0.);
1298    ]])],[
1299        AC_MSG_RESULT(yes)
1300        AC_DEFINE(HAVE_CXX11_INVERSE_HYPERBOLIC_TANGENT, 1, [Flag indicating whether compiler supports std::atanh])
1301        have_cxx11_inverse_hyperbolic_tangent=yes
1302    ],[
1303      AC_MSG_RESULT(no)
1304    ])
1305
1306
1307    # Test for asinh(complex)
1308    AC_MSG_CHECKING(for C++11 std::asinh(complex) support in <complex>)
1309    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
1310      @%:@include <complex>
1311    ]], [[
1312      std::complex<double> z(0, -2);
1313      std::complex<double> x = std::asinh(z);
1314    ]])],[
1315        AC_MSG_RESULT(yes)
1316        AC_DEFINE(HAVE_CXX11_INVERSE_HYPERBOLIC_SINE_COMPLEX, 1, [Flag indicating whether compiler supports std::asinh(complex)])
1317        have_cxx11_inverse_hyperbolic_sine_complex=yes
1318    ],[
1319      AC_MSG_RESULT(no)
1320    ])
1321
1322    # Test for acosh(complex)
1323    AC_MSG_CHECKING(for C++11 std::acosh(complex) support in <complex>)
1324    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
1325      @%:@include <complex>
1326    ]], [[
1327      std::complex<double> z(0.5, 0);
1328      std::complex<double> x = std::acosh(z);
1329    ]])],[
1330        AC_MSG_RESULT(yes)
1331        AC_DEFINE(HAVE_CXX11_INVERSE_HYPERBOLIC_COSINE_COMPLEX, 1, [Flag indicating whether compiler supports std::acosh(complex)])
1332        have_cxx11_inverse_hyperbolic_cosine_complex=yes
1333    ],[
1334      AC_MSG_RESULT(no)
1335    ])
1336
1337    # Test for atanh(complex)
1338    AC_MSG_CHECKING(for C++11 std::atanh(complex) support in <complex>)
1339    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
1340      @%:@include <complex>
1341    ]], [[
1342      std::complex<double> z(2, 0);
1343      std::complex<double> x = std::atanh(z);
1344    ]])],[
1345        AC_MSG_RESULT(yes)
1346        AC_DEFINE(HAVE_CXX11_INVERSE_HYPERBOLIC_TANGENT_COMPLEX, 1, [Flag indicating whether compiler supports std::atanh(complex)])
1347        have_cxx11_inverse_hyperbolic_tangent_complex=yes
1348    ],[
1349      AC_MSG_RESULT(no)
1350    ])
1351
1352    # Test for erf
1353    AC_MSG_CHECKING(for C++11 std::erf support in <cmath>)
1354    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
1355      @%:@include <cmath>
1356    ]], [[
1357      double val = std::erf(1.);
1358    ]])],[
1359        AC_MSG_RESULT(yes)
1360        AC_DEFINE(HAVE_CXX11_ERF, 1, [Flag indicating whether compiler supports std::erf])
1361        have_cxx11_erf=yes
1362    ],[
1363      AC_MSG_RESULT(no)
1364    ])
1365
1366
1367    # Reset the flags
1368    CXXFLAGS="$old_CXXFLAGS"
1369    AC_LANG_POP([C++])
1370
1371    AM_CONDITIONAL(HAVE_CXX11_INVERSE_HYPERBOLIC_SINE, test x$have_cxx11_inverse_hyperbolic_sine == xyes)
1372    AM_CONDITIONAL(HAVE_CXX11_INVERSE_HYPERBOLIC_COSINE, test x$have_cxx11_inverse_hyperbolic_cosine == xyes)
1373    AM_CONDITIONAL(HAVE_CXX11_INVERSE_HYPERBOLIC_TANGENT, test x$have_cxx11_inverse_hyperbolic_tangent == xyes)
1374
1375    AM_CONDITIONAL(HAVE_CXX11_INVERSE_HYPERBOLIC_SINE_COMPLEX, test x$have_cxx11_inverse_hyperbolic_sine_complex == xyes)
1376    AM_CONDITIONAL(HAVE_CXX11_INVERSE_HYPERBOLIC_COSINE_COMPLEX, test x$have_cxx11_inverse_hyperbolic_cosine_complex == xyes)
1377    AM_CONDITIONAL(HAVE_CXX11_INVERSE_HYPERBOLIC_TANGENT_COMPLEX, test x$have_cxx11_inverse_hyperbolic_tangent_complex == xyes)
1378
1379    AM_CONDITIONAL(HAVE_CXX11_ERF, test x$have_cxx11_erf == xyes)
1380  ])
1381
1382
1383AC_DEFUN([LIBMESH_TEST_CXX11_DELETED_FUNCTIONS],
1384  [
1385    have_cxx11_deleted_functions=no
1386
1387    AC_MSG_CHECKING(for C++11 deleted functions support)
1388    AC_LANG_PUSH([C++])
1389
1390    old_CXXFLAGS="$CXXFLAGS"
1391    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
1392
1393    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
1394    class Foo
1395    {
1396      Foo(const Foo &) = delete;
1397    };
1398    ]], [[
1399    ]])],[
1400        AC_MSG_RESULT(yes)
1401        AC_DEFINE(HAVE_CXX11_DELETED_FUNCTIONS, 1, [Flag indicating whether compiler supports f() = delete;])
1402        have_cxx11_deleted_functions=yes
1403    ],[
1404      AC_MSG_RESULT(no)
1405    ])
1406
1407    # Reset the flags
1408    CXXFLAGS="$old_CXXFLAGS"
1409    AC_LANG_POP([C++])
1410
1411    AM_CONDITIONAL(HAVE_CXX11_DELETED_FUNCTIONS, test x$have_cxx11_deleted_functions == xyes)
1412  ])
1413
1414
1415AC_DEFUN([LIBMESH_TEST_CXX11_DEFAULTED_FUNCTIONS],
1416  [
1417    have_cxx11_defaulted_functions=no
1418
1419    AC_MSG_CHECKING(for C++11 defaulted functions support)
1420    AC_LANG_PUSH([C++])
1421
1422    old_CXXFLAGS="$CXXFLAGS"
1423    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
1424
1425    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
1426    class Foo
1427    {
1428      Foo(const Foo &) = default;
1429      ~Foo();
1430    };
1431    Foo::~Foo() = default;
1432    ]], [[
1433    ]])],[
1434        AC_MSG_RESULT(yes)
1435        AC_DEFINE(HAVE_CXX11_DEFAULTED_FUNCTIONS, 1, [Flag indicating whether compiler supports defaulted functions])
1436        have_cxx11_defaulted_functions=yes
1437    ],[
1438      AC_MSG_RESULT(no)
1439    ])
1440
1441    # Reset the flags
1442    CXXFLAGS="$old_CXXFLAGS"
1443    AC_LANG_POP([C++])
1444
1445    AM_CONDITIONAL(HAVE_CXX11_DEFAULTED_FUNCTIONS, test x$have_cxx11_defaulted_functions == xyes)
1446  ])
1447
1448
1449AC_DEFUN([LIBMESH_TEST_CXX11_FINAL],
1450  [
1451    have_cxx11_final=no
1452
1453    AC_MSG_CHECKING(for C++11 'final' keyword support)
1454    AC_LANG_PUSH([C++])
1455
1456    old_CXXFLAGS="$CXXFLAGS"
1457    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
1458
1459    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
1460    // Test that a function can be declared final.
1461    struct A
1462    {
1463      virtual void foo() final;
1464    };
1465
1466    // Test that a struct can be declared final.
1467    struct B final : A
1468    {
1469    };
1470    ]], [[
1471    ]])],[
1472      have_cxx11_final=yes
1473    ],[
1474      have_cxx11_final=no
1475    ])
1476
1477    # Confirm that you cannot declare a non-virtual function 'final'.
1478    AS_IF([test "x$have_cxx11_final" != "xno"],
1479          [
1480            AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
1481            struct A
1482            {
1483              // Error: non-virtual function cannot be final
1484              void bar() final;
1485            };
1486            ]], [[
1487            ]])],[
1488              # If this code compiles, 'final' is not working correctly.
1489              have_cxx11_final=no
1490            ],[
1491              have_cxx11_final=yes
1492            ])
1493          ])
1494
1495    dnl Confirm that you cannot override a final function.
1496    AS_IF([test "x$have_cxx11_final" != "xno"],
1497          [
1498            AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
1499            struct A
1500            {
1501              virtual void foo() final;
1502            };
1503            struct B : A
1504            {
1505              // Error: foo cannot be overridden as it's final in A
1506              void foo();
1507            };
1508            ]], [[
1509            ]])],[
1510              # If this code compiles, 'final' is not working correctly.
1511              have_cxx11_final=no
1512            ],[
1513              have_cxx11_final=yes
1514            ])
1515          ])
1516
1517    dnl Confirm that you cannot inherit from a 'final' class.
1518    AS_IF([test "x$have_cxx11_final" != "xno"],
1519          [
1520            AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
1521            struct A
1522            {
1523            };
1524
1525            // struct B is final
1526            struct B final : A
1527            {
1528            };
1529
1530            // Error: B is final
1531            struct C : B
1532            {
1533            };
1534            ]], [[
1535            ]])],[
1536              # If this code compiles, 'final' is not working correctly.
1537              have_cxx11_final=no
1538            ],[
1539              have_cxx11_final=yes
1540            ])
1541          ])
1542
1543    # If the flag is still 'yes' after all the tests, set the #define.
1544    AS_IF([test "x$have_cxx11_final" = "xyes"],
1545          [
1546            AC_MSG_RESULT(yes)
1547            AC_DEFINE(HAVE_CXX11_FINAL, 1, [Flag indicating whether compiler supports f() final;])
1548          ],
1549          [AC_MSG_RESULT(no)])
1550
1551    # Reset the flags
1552    CXXFLAGS="$old_CXXFLAGS"
1553    AC_LANG_POP([C++])
1554
1555    AM_CONDITIONAL(HAVE_CXX11_FINAL, test x$have_cxx11_final == xyes)
1556  ])
1557
1558
1559AC_DEFUN([LIBMESH_TEST_CXX11_NULLPTR],
1560  [
1561    have_cxx11_nullptr=no
1562
1563    AC_MSG_CHECKING(for C++11 nullptr support)
1564    AC_LANG_PUSH([C++])
1565
1566    old_CXXFLAGS="$CXXFLAGS"
1567    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
1568
1569    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
1570    @%:@include <cstddef>
1571    void f(int * pi) {}
1572    void f(double * pd) {}
1573    void f(std::nullptr_t nullp) {}
1574    ]], [[
1575    // would be ambiguous without void f(nullptr_t)
1576    f(nullptr);
1577    ]])],[
1578      AC_MSG_RESULT(yes)
1579      AC_DEFINE(HAVE_CXX11_NULLPTR, 1, [Flag indicating whether compiler supports nullptr])
1580      have_cxx11_nullptr=yes
1581    ],[
1582      AC_MSG_RESULT(no)
1583    ])
1584
1585    # Reset the flags
1586    CXXFLAGS="$old_CXXFLAGS"
1587    AC_LANG_POP([C++])
1588
1589    AM_CONDITIONAL(HAVE_CXX11_NULLPTR, test x$have_cxx11_nullptr == xyes)
1590  ])
1591
1592
1593
1594AC_DEFUN([LIBMESH_TEST_CXX11_TO_STRING],
1595  [
1596    have_cxx11_to_string=no
1597
1598    AC_MSG_CHECKING(for C++11 std::to_string() support)
1599    AC_LANG_PUSH([C++])
1600
1601    old_CXXFLAGS="$CXXFLAGS"
1602    CXXFLAGS="$CXXFLAGS $switch $libmesh_CXXFLAGS"
1603
1604    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
1605      @%:@include <string>
1606    ]], [[
1607      // tiny="0.000000".  Note: std::to_string(double) is required to produce
1608      // a std::string with the same contents as std::sprintf(buf, "%f", value)
1609      // would produce, given a sufficiently large buf.  This is *different* from
1610      // what you get from a std::stringstream using default formatting and
1611      // precision flags, i.e.
1612      //   std::ostringstream oss;
1613      //   oss << 1.e-40;
1614      //   std::string tiny = oss.str();
1615      // will produce the string "1e-40".
1616      std::string tiny = std::to_string(1.e-40);
1617    ]])],[
1618        AC_MSG_RESULT(yes)
1619        AC_DEFINE(HAVE_CXX11_TO_STRING, 1, [Flag indicating whether compiler supports std::to_string()])
1620        have_cxx11_to_string=yes
1621    ],[
1622      AC_MSG_RESULT(no)
1623    ])
1624
1625    # Reset the flags
1626    CXXFLAGS="$old_CXXFLAGS"
1627    AC_LANG_POP([C++])
1628
1629    AM_CONDITIONAL(HAVE_CXX11_TO_STRING, test x$have_cxx11_to_string == xyes)
1630  ])
1631