2016-07-01 12 views
5

voglio fare quanto segue:Come posso utilizzare una funzione constexpr durante l'espansione del pacchetto?

// have a constexpr function 
template<class T> 
constexpr T square(T const i) 
{ 
    return i * i; 
} 

// transform a std::integer_sequence<> by calling the constexpr function on every integer 
template<class Fn, class T, T... values> 
static constexpr auto make_type(Fn fn, std::integer_sequence<T, values...>) 
{ 
    return std::integer_sequence<T, fn(values)...>{}; 
} 

// so that I can use it like so 
using type = decltype(make_type(square, std::integer_sequence<int, 1, 2, 3>{})); 

Tuttavia, ottengo il seguente errore:

...\main.cpp|19|error: 'fn' is not a constant expression|

risposta

5

fn non è utilizzabile in un'espressione costante - è una variabile del blocco-scope bog-standard. Devi passare il functor come tipo.

template <typename Fn, typename T, T... values> 
static constexpr std::integer_sequence<T, Fn{}(values)...> 
make_type(std::integer_sequence<T, values...>) {return {};} 

e riscrivere la funzione come

struct Square { 
    template <typename T> constexpr T operator()(T const& t) 
    {return t*t;} 
}; 
1

Oltre al fatto che constexpr non fa parte del tipo di un puntatore a funzione, square è un modello, quindi non è possibile formare un puntatore ad esso dal solito decadimento implicito.

Tuttavia, non è necessario modificare la firma della funzione make_type per farlo funzionare. Riscrivere Square come un funtore:

struct Square { 
    template<class T> 
    constexpr T operator()(T const& i) 
    { 
     return i * i; 
    } 
}; 

E chiamare in questo modo:

using type = decltype(make_type(square{}, std::integer_sequence<int, 1, 2, 3>{})); 

In C++ 17 si sarà in grado di utilizzare un constexpr lambda:

constexpr auto square = [](auto const& i) { return i * i; }; 

using type = decltype(make_type(square, std::integer_sequence<int, 1, 2, 3>{})); 
Problemi correlati