基于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 ++标准中未定义?
答案 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
。