Использование SFINAE для обнаружения статического constexpr

Я пытаюсь применить метод из http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Member_Detector, чтобы проверить, имеет ли тип статический элемент constexpr.

Вот что я пробовал:

#include <stddef.h>
#include <stdint.h>
#include <iostream>

struct Foo {
    static constexpr uint32_t magic = 100;
};

struct Bar {
    static constexpr uint32_t bla = 100;
};

template <class T>
class HasMember_magic {
  private:
    using Yes = char[2];
    using No = char[1];

    struct Fallback {
        static constexpr uint32_t magic = 0;
    };
    struct Derived : T, Fallback {};

    template <class U>
    static No& test(decltype(U::magic)*);

    template <typename U>
    static Yes& test(U*);

  public:
    static constexpr bool RESULT =
            sizeof(test<Derived>(nullptr)) == sizeof(Yes);
};

int main(int argc, char* argv[]) {
    std::cout << HasMember_magic<Foo>::RESULT << std::endl;
    std::cout << HasMember_magic<Bar>::RESULT << std::endl;

    return 0;
}

Он отлично работает с gcc:

$ g++  -std=c++11 test.cxx 
$ ./a.out 
1 
0

Но clang жалуется:

$ clang++ -std=c++11 test.cxx
test.cxx:32:24: error: call to 'test' is ambiguous
                sizeof(test<Derived>(nullptr)) == sizeof(Yes);
                       ^~~~~~~~~~~~~
test.cxx:37:22: note: in instantiation of template class 'HasMember_magic<Bar>' requested here
        std::cout << HasMember_magic<Bar>::RESULT << std::endl;
                     ^
test.cxx:25:20: note: candidate function [with U = HasMember_magic<Bar>::Derived]
        static No& test(decltype(U::magic)*);
                   ^
test.cxx:28:21: note: candidate function [with U = HasMember_magic<Bar>::Derived]
        static Yes& test(U*);
                    ^
1 error generated.
$ clang++ --version
clang version 3.4 (tags/RELEASE_34/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
$

Идея получения адреса static constexpr мне не кажется правильной, поэтому я не удивлена, увидев проблемы.

Итак, как правильно это сделать? Решение должно работать как в gcc, так и в clang.


person Allan    schedule 06.02.2014    source источник
comment
Я понятия не имею, как это должно работать нормально. Похоже на ошибку в GCC. (Вот подсказка для возможного решения: template <uint32_t> struct requires_a_constant {}; decltype(requires_a_constant<U::magic>).   -  person R. Martinho Fernandes    schedule 06.02.2014
comment
Обратите внимание, что decltype(T::name) не гарантирует, что name будет constexpr. Его нужно использовать в контексте, который требует constexpr.   -  person Xeo    schedule 06.02.2014