Clang问题:用SFINAE检测constexpr函数指针

时间:2014-03-09 16:00:37

标签: c++11 template-meta-programming

基于Detecting constexpr with SFINAE中的答案我试图使用SFINAE来检查我的班级中是否存在'constexpr'。

问题是constexpr是一个函数指针:

#include <type_traits>
#include <iostream>

typedef int (*ptr_t)();
int bar() { return 9; }

struct Foo {
    static constexpr ptr_t ptr = &bar;
};

namespace detail {
template <ptr_t>
struct sfinae_true : std::true_type {};

template <class T>
sfinae_true<T::ptr> check(int);

// Commented out to see why clang was not evaluating to true. This should only be
// a comment when debugging!
// template <class>
// std::false_type check(...);
}  // detail::

template <class T>
struct has_constexpr_f : decltype(detail::check<T>(0)) {};

int main(int argc, char *argv[]) {
    std::cout << has_constexpr_f<Foo>::value << std::endl;
    return 0;
}

使用gcc似乎工作正常,但clang抱怨:

test.cxx:23:39: error: no matching function for call to 'check'
    struct has_constexpr_f : decltype(detail::check<T>(0)) {};
                                      ^~~~~~~~~~~~~~~~
test.cxx:26:22: note: in instantiation of template class 'has_constexpr_f<Foo>' requested here
        std::cout << has_constexpr_f<Foo>::value << std::endl;
                     ^
test.cxx:16:25: note: candidate template ignored: substitution failure [with T = Foo]: non-type template argument for template parameter of pointer type 'ptr_t' (aka 'int (*)()') must have its address taken
    sfinae_true<T::ptr> check(int);
                ~       ^
1 error generated.

问题1:有人可以提出一种方法,这对Clang和GCC都有效吗?

Q2:这是gcc,clang中的错误还是在c ++标准中未定义?

1 个答案:

答案 0 :(得分:0)

这不是clang中的错误,而是对指针类型的非类型模板参数的参数的不幸限制(请参阅pointer as non-type template argument)。基本上,您只能使用&something形式的参数:[temp.arg.nontype] / 1(来自n3797)

  

[如果template-parameter是一个指针,它的参数可以是]一个常量表达式(5.19),用于指定一个地址   具有静态存储持续时间的完整对象和外部或   内部联系或具有外部或内部联系的功能,   包括函数模板和函数 template-ids 但不包括   非静态类成员,表示(忽略括号)为&    id-expression ,其中 id-expression 是对象的名称或   功能,除了&amp;如果名称引用a,则可以省略   函数或数组,如果相应则应省略    template-parameter 是一个参考;或[..]

[强调我的]

但是,您可以在具有非指针类型的常量表达式中使用函数指针,例如布尔表达式,例如

T::ptr != nullptr

这适用于clang ++ 3.5和g ++ 4.8.2:

#include <type_traits>
#include <iostream>

typedef int (*ptr_t)();
int bar() { return 9; }

struct Foo0 {
    static constexpr ptr_t ptr = &bar;
};

struct Foo1 {
    static const ptr_t ptr;
};
ptr_t const Foo1::ptr = &bar;

struct Foo2 {
    static const ptr_t ptr;
};
//ptr_t const Foo2::ptr = nullptr;

namespace detail
{
    template <bool>
    struct sfinae_true : std::true_type {};

    template <class T>
    sfinae_true<(T::ptr != nullptr)> check(int);
    // the result of the comparison does not care

    template <class>
    std::false_type check(...);
}  // detail::

template <class T>
struct has_constexpr_f : decltype(detail::check<T>(0)) {};

int main(int argc, char *argv[]) {
    std::cout << std::boolalpha << has_constexpr_f<Foo0>::value << std::endl;
    std::cout << std::boolalpha << has_constexpr_f<Foo1>::value << std::endl;
    std::cout << std::boolalpha << has_constexpr_f<Foo2>::value << std::endl;
    return 0;
}

请注意,第二个输出(Foo1)的clang ++和g ++之间存在差异:g ++表示true,clang ++表示false