2017-02-09 15 views
1

Рассмотрим этот код:Позвони constexpr функцию принятия массива не удается скомпилировать

#include <array> 

template < int... Ints > 
constexpr std::array<int,sizeof...(Ints)> theIntArray = {Ints...}; 

template < size_t NN > 
constexpr void test(const std::array<int,NN>& xx) 
{ 
    theIntArray<xx[0]>; 
} 

constexpr std::array<int,2> aa = {10,20}; 

int main() 
{ 
    theIntArray<aa[0]>; // passes 
    test(aa); // FAILS ?! 

    return 0; 
} 

В функции main() первая линия проходит в то время как вторая линия не может со странным сообщением об ошибке:

error: ‘* & xx’ is not a constant expression 
note: in template argument for type ‘int’ 

Я использую gcc-7.0.1, и вы можете найти живой пример here.

Это в соответствии со стандартом или это ошибка? Что делает вторую строку неудачной, пока проходит первая строка?

ответ

2

Все функции constexpr должны быть действительными как с аргументами constexpr, так и без constexpr. Или, короче говоря, аргументы функции constexpr не являются constexpr внутри тела, но если они являются constexpr вне тела функции, то в зависимости от них вычисления certian могут быть возвращены из функции constexpr.

theIntArray<xx[0]>; 

это действительно только синтаксис, если xx[0] является constexpr, но внутри тела функции xx является неconstexpr.

template < size_t NN, std::array<int,NN> const& xx > 
constexpr void test() 
{ 
    theIntArray<xx[0]>; 
} 

live example.

+0

TIL добавляет константу-ссылку к типу литерала, чтобы имитировать определяемый пользователем параметр непигового шаблона. upvoted. – TemplateRex

1

Разница в том, что параметр функции constexpr не существует. То есть, вы не можете сделать

constexpr auto fun(int x) { 
    constexpr y = x; 
    return y; 
} 

и ни вы можете использовать параметр функции xx[0] в качестве шаблона-параметра не типа внутри функции. Это отличается от aa[0], потому что это оценивается вне функции.

Единственный способ сделать то, что вы хотите, - сделать параметр функции несимметричным шаблоном. Для этого см. Ответ @Yakk, где он использует const-reference для массива constexpr в качестве параметра шаблона непигового типа.