2016-07-01 6 views
5

Ich möchte folgendes tun:Wie kann ich während der Paketerweiterung eine constexpr-Funktion verwenden?

// 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>{})); 

Allerdings bekomme ich folgende Fehlermeldung:

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

Antwort

5

fn ist in einem konstanten Ausdruck nicht verwendbar - es ist ein Moor-Standard-Block-scope Variable. Du musst den Funktor als Typ übergeben.

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

und schreiben Sie Ihre Funktion als

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

Neben der Tatsache, dass constexpr nicht Teil der Art eines Funktionszeiger ist, square eine Schablone, so dass Sie nicht einen Zeiger darauf bilden kann durch den üblichen impliziten Verfall.

Es ist jedoch nicht notwendig, die Signatur Ihrer make_type Funktion zu ändern, damit dies funktioniert. Rewrite Square als Funktor:

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

Und es so nennen:

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

In C++ 17 Sie in der Lage, ein constexpr Lambda zu verwenden:

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

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