That's not a bug in clang, but an unfortunate restriction of arguments for non-type template parameters of pointer type (see pointer as non-type template argument). Essentially, you can only use arguments of the form &something
: [temp.arg.nontype]/1 (from n3797)
[if the template-parameter is a pointer, its argument can be] a constant expression (5.19) that designates the address of a complete object with static storage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as
&
id-expression, where the id-expression is the name of an object or function, except that the & may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; or [..]
[emphasis mine]
You can however, use a function pointer in a constant expression that has a non-pointer type, for example a boolean expression such as
T::ptr != nullptr
This works under clang++3.5 and 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;
}
Note there's a difference between clang++ and g++ for the second output (Foo1
): g++ says true
, clang++ says false
.