Ошибка C ++ 0x с constexpr и возвращающей функцией шаблона - PullRequest
10 голосов
/ 19 июля 2011

Я попытался найти решение для проблемы вопроса Вычисление типа не типового параметра шаблона C ++ , которое не включает параметр шаблона для вызова f, но неявно выбирает правильный тип для шаблона параметр.

Так как constexpr должен гарантировать, что функция содержит только константы времени компиляции и оценивается во время компиляции (по крайней мере, так я думаю), я подумал, что это может быть решением этой проблемы. Итак, я придумал это:

template <class T, T VALUE> void f() {}

//first i tried this:
template <class T> auto get_f(T t) -> decltype( &f<T,t> ) { return f<T,t>; }

//second try:
template <class T> constexpr void (&get_f( T t ))()  { return f<T,t>; }

int main()
{
    get_f(10)(); //gets correct f and calls it
}

Первая версия генерирует следующую ошибку:

error: use of parameter 't' outside function body

, что на самом деле сбивает с толку, поскольку использование параметров в операторе decltype конечного возвращаемого типа должно быть в порядке?

Вторая версия генерирует следующую ошибку:

error: invalid initialization of non-const reference of type 'void (&)()' 
       from an rvalue of type '<unresolved overloaded function type>'

, что немного запутанно, так как я полностью квалифицирован f в get_f. Я ожидал бы такого рода сообщения об ошибках, если бы у меня не было constexpr. Так у меня есть неверное понимание того, что делает constexpr, или реализация GCC для C ++ 0x некорректна для этого случая?

Я использую GCC 4.6.2

1 Ответ

5 голосов
/ 19 июля 2011

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

Функция constexpr может использоваться в контексте константного выражения, но не ограничивается одним. В этом отношении они отличаются от метафункции и регулярной функции. Рассмотрим проблему возврата наследника целого числа:

// Regular function
int f(int i)
{ return i + 1; }

// Regular metafunction
template<int I>
struct g {
    static constexpr auto value = I + 1;
};

// constexpr function
constexpr int h(int i)
{ return i + 1; }

// Then...
{
    // runtime context: the metafunction can't be used
    int i;
    std::cin >> i;

    f(i); // Okay
    g<i>::value; // Invalid
    h(i); // Okay

    // compile time context: the regular function can't be used
    char a[f(42)]; // Invalid
    char b[g<42>::value]; // Okay
    char c[h(42)]; // Okay
}

constexpr имеет другие применения (например, конструкторы), но когда дело доходит до constexpr функций, это суть этого: некоторые функции должны быть доступны как во время выполнения, так и в постоянном контексте, потому что некоторые вычисления доступны в обоих. Можно вычислить i + 1, является ли i константой времени компиляции или извлечено из std::cin.

Это означает, что внутри тела функции constexpr параметры не сами являются константными выражениями. Так что то, что вы пытаетесь, невозможно. Ваша функция не может справиться с

int i;
std::cin >> i;
get_f(i); // what's the return type?

и нарушение происходит здесь:

constexpr auto get_f(T t)
-> decltype( &f<T,t> ) // <-

Поскольку t не является константным выражением в соответствии с правилами языка (несмотря ни на что, даже если вы на самом деле передаете только константные выражения в), оно не может отображаться как второй шаблон параметр f.

(А на более широком рисунке это означает, что нет, вы не можете использовать вычитание аргументов из шаблонов function для удобной передачи не типового параметра в шаблон class .)

...