Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Pointer Type Cast Does not Work on Template Non-type Parameters

I have the following code:

template <const char *p>
struct A{};

template <int i>
struct E{};

extern constexpr int i = 0;
constexpr float f = 0.f;
extern constexpr char c = 0;
int main(int argc, const char *argv[])
{
  A<&c> b; //works
  A<(const char *)(&i)> a; //Error: could not convert template argument ‘(const char*)(& i)’ to ‘const char*’
  E<(int)f> e; //works
  return 0;
}

why the line A<(const char *)(&i)> a; is wrong? I compiled it with g++-4.6.1 with -std=c++0x.

EDIT: As Charles suggested that reinterpret_cast is not permitted in a constant expression, I change the above code to the following:

struct Base{};
struct Derived : public Base {};

template <const Base *p>
struct A{};

extern constexpr Base base = {};
extern constexpr Derived derived = {};
A<&base> a; //works
A<(const Base*)&derived> b; //error: could not convert template argument ‘(const Base*)(& derived)’ to ‘const Base*’

Therefore, not only reinterpret_cast is not allowed. Using A<static_cast<const base*>(&derived) yields the same error.

To @BЈовић:

  A<(const Base*)(0)> b; // error: could not convert template argument ‘0u’ to ‘const Base*’
like image 322
Danqi Wang Avatar asked Aug 27 '12 07:08

Danqi Wang


1 Answers

As for "the standard says so" answers, look in the comments.

The real question is Why would this not be allowed?

It makes a lot of sense to categorically refuse type conversions in template arguments, because what you are really interested in is the value of the template argument. Type conversions however can become arbitrarily complicated and are not forced to be constexprs. The standard (apparently) simply doesn't make an exception for built-in (primitive) types.

Note that your E<(int)f> example is also refuted by clang with the reason:

error: non-type template argument of type 'int' is not an integral constant expression

Why gcc allows this is dubious, but I'd assume it allows you to use constexprs that you could explicitly declare. Note that this is not possible to sneak the address of i in the parameter list of A.

like image 160
bitmask Avatar answered Oct 06 '22 01:10

bitmask