Pointer as Non-Type Template Argument

pointer non-type template parameter

For 1.:

From [temp.arg.nontype]

1 A template-argument for a non-type template-parameter shall be a converted constant expression (5.20) of the type of the template-parameter. For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):

[...]

(1.3) — a string literal (2.13.5),

s2 holds the address of a string literal, and so cannot be used as the parameter here. s1 on the other hand is an array of char that has been initialized with a string literal, but the value of s1 (when converted to const char*) doesn't point to the string literal used in the initialization.

For 2.:

Function pointers perhaps? Still I can't say I've ever used a pointer as a non-type parameter.

Is passing of a function pointer through a class type in non-type template parameter allowed in C++20?

Which compiler is correct here?

Clang is correct, the code as written is valid.

GCC not handling that specific case is a known issue.

Passing a function pointer as non-type template parameter

template<class T, T t>
struct constant_t:std::integral_constant<T,t>{
constexpr operator T()const { return t; }
constexpr constant_t(){}
};

#define TYPEDARG(...) \
typename std::decay<decltype(__VA_ARGS__)>::type, \
__VA_ARGS__

Now constant_t<TYPEDARG(foo)> is a type whose instances can be invoked if foo is a non-overloaded function and they call foo.

In c++17 this becomes:

template<auto x>
using constant_t=std::integral_constant<std::decay_t<decltype(x)>,x>;

and use is simply constant_t<foo>, without all that extra noise.

template<class Fn, class R, class... Args>
R test(Args&&... args) {
return Fn{}(std::forward<Args>(args)...);
}

int foo( int a, int b ) { return a+b; }

int r = test< constant_t<TYPEDARG(foo)>, int, int, int >( 3, 4 );

Pointer to (data) member as non-type template parameter for instance with automatic storage duration / without linkage

Is the compiler (by direct or indirect, e.g. the above, standard requirements) required to sort this out by itself, storing only (compile-time) address offsets between the members, rather than actual addresses?

Pretty much. It's an "offset" even outside of a compile time context. Pointers to members are not like regular pointers. They designate members, not objects. That also means that the verbiage about valid pointer targets does not relate to pointer-to-members.

That's why to produce an actual lvalue out of them, one must complete the picture with something that refers to an object, such as we do in this->*counter. If you were to try and use this->*counter where a constant expression is required, the compiler would have complained, but it would have been about this, and not counter.

Their distinct nature is what allows them to uncondionally be compile time constants. There's no object that the compiler must check as a valid target.

syntax variants for function pointer as non type template arg

You are going to declare a non-type template parameter. You can write

template < bool( *ptr )( int, int ) >
void Check()
{
ptr( 1, 1 );
}

Inferring type and class when passing a pointer to data member as a non-type template argument

You can use a helper to get the type of the class and the member from the type of a member pointer:

template <typename T> struct type_from_member;

template <typename Cls,typename M>
struct type_from_member<M Cls::*> {
using class_type = Cls;
using member_type = M;
};

Then you can use auto and inherit from the helper:

template <auto member> struct Mem : type_from_member<decltype(member)> {};

using B = Mem<&Struct::x>;

static_assert( std::is_same_v<B::member_type,int>);
static_assert( std::is_same_v<B::class_type,Struct>);


Related Topics



Leave a reply



Submit