Подтвердить что ты не робот

Почему тип указателя Cast не работает с шаблоном Параметры непикового типа

У меня есть следующий код:

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;
}

почему строка A<(const char *)(&i)> a; неверна? Я скомпилировал его с g++ - 4.6.1 с -std = С++ 0x.

EDIT: поскольку Чарльз предположил, что reinterpret_cast не допускается в постоянном выражении, я изменяю приведенный выше код на следующее:

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*’

Следовательно, не только reinterpret_cast не допускается. Использование A<static_cast<const base*>(&derived) дает ту же ошибку.

To @BЈовић:

  A<(const Base*)(0)> b; // error: could not convert template argument ‘0u’ to ‘const Base*’
4b9b3361

Ответ 1

Что касается ответов "стандарт говорит так", посмотрите комментарии.

Реальный вопрос: почему это не допустимо?

Это имеет смысл категорически отказаться от преобразования типов в аргументах шаблона, потому что то, что вас действительно интересует, - это значение аргумента шаблона. Преобразования типов, однако, могут стать произвольно сложными и не должны быть constexpr s. Стандартный (по-видимому) просто не делает исключение для встроенных (примитивных) типов.

Обратите внимание, что ваш пример E<(int)f> также опровергается clang по причине:

error: аргумент типа non-type типа 'int' не является интегральным постоянным выражением

Почему gcc позволяет это сомнительно, но я бы предположил, что он позволяет использовать constexpr, который вы можете явно объявить. Обратите внимание, что это невозможно, чтобы прокрасть адрес i в списке параметров A.