calculating data compile time with template metaprogramming - c++

Suppose we have code like this. It works well and pre-calculate first 5 Fibonacci numbers.
#include <iostream>
template <int T>
struct fib;
template <>
struct fib<0>{
constexpr static int value = 1;
};
template <>
struct fib<1>{
constexpr static int value = 1;
};
template <int I>
struct fib{
constexpr static int value = fib<I - 1>::value + fib<I - 2>::value;
};
int main(){
std::cout << fib<0>::value << std::endl;
std::cout << fib<1>::value << std::endl;
std::cout << fib<2>::value << std::endl;
std::cout << fib<3>::value << std::endl;
std::cout << fib<4>::value << std::endl;
std::cout << fib<5>::value << std::endl;
}
However there is "small" problem with it.
What if we need to use this for values, that are not known at compile time?
For few values we can do this:
const int max = 5;
int getData(){
return 5; // return value between 0 and max.
}
int something(){
switch(getData()){
case 0: return fib<0>::value;
case 1: return fib<1>::value;
case 2: return fib<2>::value;
case 3: return fib<3>::value;
case 4: return fib<4>::value;
case 5: return fib<5>::value;
}
}
This will works OK for 5 values, but what if we have 150 or 300?
Is not really serious to change the code with 300 rows...
What could be the workaround here?

If you need to use a value at runtime that isn't known at compile time, you can't compute it at compile time. Obvious.
But... if you can impose a top value to values needed, you can compute all values (from zero to top) at compile time and store them in an std::array.
In the following example I have modified your fib structs (to use a std::size_t index and a template type (with default unsigned long) for the value) and I have added a templated struct fibVals that contain an std::array that is initialized using fib<n>::value
The following main() show that is possible to define a constexpr fibvals<N> (with N == 20 in the example) to compute (at compile time) all fib<n> values in range [0,N[.
#include <array>
#include <utility>
#include <iostream>
template <std::size_t, typename T = unsigned long>
struct fib;
template <typename T>
struct fib<0U, T>
{ constexpr static T value { T(1) }; };
template <typename T>
struct fib<1U, T>
{ constexpr static T value { T(1) }; };
template <std::size_t I, typename T>
struct fib
{ constexpr static T value { fib<I-1U>::value + fib<I-2U>::value }; };
template <std::size_t I, typename T = unsigned long>
struct fibVals
{
const std::array<T, I> vals;
template <std::size_t ... Is>
constexpr fibVals ( std::index_sequence<Is...> const & )
: vals { { fib<Is, T>::value ... } }
{ }
constexpr fibVals () : fibVals { std::make_index_sequence<I> { } }
{ }
};
int main()
{
constexpr fibVals<20> fv;
for ( auto ui = 0U ; ui < fv.vals.size() ; ++ui )
std::cout << "fib(" << ui << ") = " << fv.vals[ui] << std::endl;
}
Unfortunately this example use std::make_index_sequence<I> and std::index_sequence<Is...> that are C++14 features.
If you want implement struct fibVals in C++11, you can implement the following structs struct indexSeq and struct indexSeqHelper, to substitute std::index_sequence<Is...> and std::make_index_sequence<I>
template <std::size_t ...>
struct indexSeq
{ };
template <std::size_t N, std::size_t ... Next>
struct indexSeqHelper
{ using type = typename indexSeqHelper<N-1U, N-1U, Next ... >::type; };
template <std::size_t ... Next >
struct indexSeqHelper<0U, Next ... >
{ using type = indexSeq<Next ... >; };
and implement fibVals constructors as follows
template <std::size_t ... Is>
constexpr fibVals ( indexSeq<Is...> const & )
: vals { { fib<Is, T>::value ... } }
{ }
constexpr fibVals () : fibVals { typename indexSeqHelper<I>::type { } }
{ }

Templates are evaluated at compile time, so there is no solution with templates that works at runtime.
You can make a constexpr function, which may be evaluated at compile time, depending on the value passed. Obviously, a runtime value may not be computed at compile time, as it is not known at compile time.

Related

Checking if template specialization of member function exists [duplicate]

Is there a way to establish at compile time if a certain function template was specialized?
For example, assume the following function template:
template<size_t N>
void foo();
I want to test if foo<42> was specialized. Note that the declaration above doesn't contain any default implementation.
I tried SFINAE but couldn't find a condition on the function that the compiler cannot deduce from its declaration.
Is there a way to establish in compile time if a certain template function was specialized?
With a function... I don't think so.
But if you create a functor, you can add a static const member (is_specialized, in the following example) that can give you this information
#include <iostream>
template <std::size_t N>
struct foo
{
static constexpr bool is_specialized { false };
void operator() () const
{ std::cout << "- generic (" << N << ") foo struct" << std::endl; }
};
template <>
struct foo<42U>
{
static constexpr bool is_specialized { true };
void operator() () const
{ std::cout << "- specialized (42) foo struct" << std::endl; }
};
int main()
{
foo<17U>()(); // print - generic (17) foo struct
foo<42U>()(); // print - specialized (42) foo struct
std::cout << foo<17U>::is_specialized << std::endl; // print 0
std::cout << foo<42U>::is_specialized << std::endl; // print 1
}
--- EDIT ---
Following the suggestion from Quentin (thanks again!) I've developed another functor-based solution that use something, to detect if the functor is generic or specialize, that is added only in the generic functor. In this case, a type instead a bool constant.
template <std::size_t N>
struct foo
{
// im_not_specialized is added only in the generic version!
using im_not_specialized = void;
void operator () () const
{ std::cout << "- generic (" << N << ") foo struct" << std::endl; }
};
template <>
struct foo<42U>
{
void operator () () const
{ std::cout << "- specialized (42) foo struct" << std::endl; }
};
This type can be used via SFINAE and I propose an example based on a constexpr isSpecialized() template function (with an helper function)
template <typename F>
constexpr bool isSpecializedHelper
(int, typename F::im_not_specialized const * = nullptr)
{ return false; }
template <typename F>
constexpr bool isSpecializedHelper (long)
{ return true; }
template <typename F>
constexpr bool isSpecialized ()
{ return isSpecializedHelper<F>(0); }
This require a little more work but isSpecialized() can be reused with different functors (im_not_specialized type based)
The following is a full working example
#include <iostream>
template <std::size_t N>
struct foo
{
// im_not_specialized is added only in the generic version!
using im_not_specialized = void;
void operator () () const
{ std::cout << "- generic (" << N << ") foo struct" << std::endl; }
};
template <>
struct foo<42U>
{
void operator () () const
{ std::cout << "- specialized (42) foo struct" << std::endl; }
};
template <typename F>
constexpr bool isSpecializedHelper
(int, typename F::im_not_specialized const * = nullptr)
{ return false; }
template <typename F>
constexpr bool isSpecializedHelper (long)
{ return true; }
template <typename F>
constexpr bool isSpecialized ()
{ return isSpecializedHelper<F>(0); }
int main()
{
foo<17U>()(); // print - generic (17) foo struct
foo<42U>()(); // print - specialized (42) foo struct
constexpr auto isSp17 = isSpecialized<foo<17U>>();
constexpr auto isSp42 = isSpecialized<foo<42U>>();
std::cout << isSp17 << std::endl; // print 0
std::cout << isSp42 << std::endl; // print 1
}
If you mark the base function as deleted (= delete), you can detect if it has been specialized using SFINAE (assuming the specialization itself is not deleted)
An expression like decltype(foo<N>()) will result in a substitution failure if foo<N> is marked as deleted. If you provide a specialization that is not deleted on the other hand the expression will not result in an error.
Using this you can create a simple trait class to check if foo has been specialized for a specific set of template parameters:
template<std::size_t N, class = void>
struct is_foo_specialized : std::false_type {};
template<std::size_t N>
struct is_foo_specialized<N, decltype(foo<N>(), void())> : std::true_type {};
1. Basic examples
C++11: godbolt
#include <type_traits>
template<std::size_t N>
void foo() = delete;
template<>
void foo<1>() { }
template<std::size_t N, class = void>
struct is_foo_specialized : std::false_type {};
template<std::size_t N>
struct is_foo_specialized<N, decltype(foo<N>(), void())> : std::true_type {};
int main()
{
static_assert(!is_foo_specialized<0>::value, ""); // foo<0> is not specialized
static_assert(is_foo_specialized<1>::value, ""); // foo<1> IS specialized
}
With C++20 you could also use a concept for this, e.g.: godbolt
#include <type_traits>
template<std::size_t N>
void foo() = delete;
template<>
void foo<1>() { }
template<std::size_t N>
concept is_foo_specialized = requires { foo<N>(); };
int main()
{
static_assert(!is_foo_specialized<0>); // foo<0> is not specialized
static_assert(is_foo_specialized<1>); // foo<1> IS specialized
}
2. Providing a default implementation
Due to the function being = delete'd it can't have a default implementation.
If you do require a default implementation for the function, you could use 2 functions instead:
one that is = delete'd (so SFINAE can detect it)
and another one that implements the default behaviour and forwards to the other if a specialization exists
C++11: godbolt
#include <type_traits>
#include <iostream>
template<std::size_t N>
void foo_specialized() = delete;
template<>
void foo_specialized<1>() { std::cout << "CUSTOMIZED!" << std::endl; }
template<std::size_t N, class = void>
struct is_foo_specialized : std::false_type {};
template<std::size_t N>
struct is_foo_specialized<N, decltype(foo_specialized<N>(), void())> : std::true_type {};
template<std::size_t N>
typename std::enable_if<!is_foo_specialized<N>::value>::type foo() {
std::cout << "DEFAULT!" << std::endl;
}
template<std::size_t N>
typename std::enable_if<is_foo_specialized<N>::value>::type foo() {
foo_specialized<N>();
}
int main()
{
foo<0>(); // -> DEFAULT!
foo<1>(); // -> CUSTOMIZED!
}
Or with C++20: godbolt
#include <type_traits>
#include <iostream>
template<std::size_t N>
void foo_specialize() = delete;
template<>
void foo_specialize<1>() { std::cout << "CUSTOMIZED!" << std::endl; }
template<std::size_t N>
concept is_foo_specialized = requires { foo_specialize<N>(); };
template<std::size_t N> requires (!is_foo_specialized<N>)
void foo() {
std::cout << "DEFAULT!" << std::endl;
}
template<std::size_t N> requires (is_foo_specialized<N>)
void foo() {
foo_specialize<N>();
}
int main()
{
foo<0>(); // -> DEFAULT!
foo<1>(); // -> CUSTOMIZED!
}
3. Compile-time shenanigans
This can of course also be used to iterate the specializations (within a certain limit) - or like you asked in the comments to find the nearest specialization of the function.
nearest_foo_specialized in this example will iterate over a range of values for N and check if a specialization of foo exists for this value.
N is the value where we want to start the search
SearchRange determines how many specializations will be checked (both up and down) from the provided N value (in this example we check for N's +/- 10)
CurrentDistance keeps track how far we've already searched from our starting N value, so we don't exceed the specified SearchRange
The last template parameter is used for SFINAE
e.g.:
nearest_foo_specialized<100, 10> would check for specializations of foo between N = 90 and N = 110, returning the one that is closer to 100 (prefering lower N values in case of a draw)
Example C++11: godbolt
#include <type_traits>
#include <iostream>
#include <utility>
template<std::size_t N>
void foo() = delete;
template<>
void foo<5>() { std::cout << 5 << std::endl; }
template<>
void foo<10>() { std::cout << 10 << std::endl; }
template<>
void foo<15>() { std::cout << 15 << std::endl; }
template<std::size_t N, class = void>
struct is_foo_specialized : std::false_type {};
template<std::size_t N>
struct is_foo_specialized<N, decltype(foo<N>(), void())> : std::true_type {};
template<std::size_t N, std::size_t SearchRange = 10, std::size_t CurrentDistance = 0, class = void>
struct nearest_foo_specialized {
static const std::size_t index = 0; // an index for which foo<> is specialized, if value is true.
static const std::size_t distance = CurrentDistance; // distance from original N
static const bool value = false; // have we found a specialization yet?
};
// Found a match -> Report Success
template<std::size_t N, std::size_t SearchRange, std::size_t CurrentDistance>
struct nearest_foo_specialized<N, SearchRange, CurrentDistance, typename std::enable_if< CurrentDistance <= SearchRange && is_foo_specialized<N>::value >::type> {
static const std::size_t index = N;
static const std::size_t distance = CurrentDistance;
static const bool value = true;
};
// No match found -> recurse until SearchRange limit
template<std::size_t N, std::size_t SearchRange, std::size_t CurrentDistance>
struct nearest_foo_specialized<N, SearchRange, CurrentDistance, typename std::enable_if< CurrentDistance < SearchRange && !is_foo_specialized<N>::value >::type> {
typedef nearest_foo_specialized<N - 1, SearchRange, CurrentDistance + 1> down;
typedef nearest_foo_specialized<N + 1, SearchRange, CurrentDistance + 1> up;
static const std::size_t distance = down::distance < up::distance ? down::distance : up::distance;
static const std::size_t index = down::distance == distance && down::value ? down::index : up::index;
static const std::size_t value = down::distance == distance && down::value ? down::value : up::value;
};
// calls the nearest foo() specialization (up to 10 away from the specified N)
template<std::size_t N>
typename std::enable_if<nearest_foo_specialized<N>::value>::type call_nearest_foo() {
foo<nearest_foo_specialized<N>::index>();
}
template<std::size_t N>
typename std::enable_if<!nearest_foo_specialized<N>::value>::type call_nearest_foo() {
static_assert(N!=N, "No nearest foo() specialization found!");
}
int main() {
call_nearest_foo<7>(); // calls foo<5>()
call_nearest_foo<8>(); // calls foo<10>()
call_nearest_foo<11>(); // calls foo<10>()
call_nearest_foo<15>(); // calls foo<15>()
call_nearest_foo<25>(); // calls foo<15>()
// call_nearest_foo<26>(); // error: No nearest foo() (only searching up to 10 up / down)
}

count std::optional types in variadic template tuple

I've got a parameter pack saved as a tuple in some function traits struct.
How can I find out, how many of those parameters are std::optional types?
I tried to write a function to check each argument with a fold expression, but this doesn't work as I only pass a single template type which is the tuple itself.
void foo1(){}
void foo2(int,float){}
void foo3(int, std::optional<int>, float, std::optional<int>){}
void foo4(int, std::optional<int>, bool){}
template<typename R, typename... TArgs>
struct ftraits<R(TArgs...)>
{
using ret = R;
using args = std::tuple<TArgs...>;
};
template<typename T>
struct is_optional : std::false_type
{
};
template<typename T>
struct is_optional<std::optional<T>> : std::true_type
{
};
template<typename... Ts>
constexpr auto optional_count() -> std::size_t
{
// doesn't work since Ts is a single parameter with std::tuple<...>
return (0 + ... + (is_optional<Ts>::value ? 1 : 0));
}
int main() {
using t1 = typename ftraits<decltype(foo1)>::args;
std::cout << optional_count<t1>() << std::endl; // should print 0
using t2 = typename ftraits<decltype(foo2)>::args;
std::cout << optional_count<t2>() << std::endl; // should print 0
using t3 = typename ftraits<decltype(foo3)>::args;
std::cout << optional_count<t3>() << std::endl; // should print 2
using t4 = typename ftraits<decltype(foo4)>::args;
std::cout << optional_count<t4>() << std::endl; // should print 1
}
You can use template partial specialization to get element types of the tuple and reuse the fold-expression
template<typename>
struct optional_count_impl;
template<typename... Ts>
struct optional_count_impl<std::tuple<Ts...>> {
constexpr static std::size_t count =
(0 + ... + (is_optional<Ts>::value ? 1 : 0));
};
template<typename Tuple>
constexpr auto optional_count() -> std::size_t {
return optional_count_impl<Tuple>::count;
}
Demo
You can get the size of the tuple using std::tuple_size, then iterate over all its members using a recursive template. In that template, you can pretend to construct an instance of the tuple using std::declval, get the value at the current index using std::get, and then finally get the type of that value using decltype.
Example implementation:
#include <optional>
#include <tuple>
#include <utility>
template<typename T>
struct is_optional : std::false_type {};
template<typename T>
struct is_optional<std::optional<T>> : std::true_type {};
template<typename Tuple, size_t i>
constexpr size_t optional_count_impl() {
size_t val = is_optional<std::remove_reference_t<decltype(std::get<i>(std::declval<Tuple>()))>>::value ? 1 : 0;
if constexpr (i) {
val += optional_count_impl<Tuple, i - 1>();
}
return val;
}
template<typename Tuple>
constexpr size_t optional_count() {
const size_t tuple_size = std::tuple_size<Tuple>::value;
if constexpr (tuple_size == 0) {
return 0;
} else {
return optional_count_impl<Tuple, tuple_size - 1>();
}
}
using Tup1 = std::tuple<int, int, std::optional<size_t>, bool, std::optional<bool>, std::optional<std::optional<int>>>;
int main() {
return optional_count<Tup1>();
}

How to check if a function template has been specialized?

Is there a way to establish at compile time if a certain function template was specialized?
For example, assume the following function template:
template<size_t N>
void foo();
I want to test if foo<42> was specialized. Note that the declaration above doesn't contain any default implementation.
I tried SFINAE but couldn't find a condition on the function that the compiler cannot deduce from its declaration.
Is there a way to establish in compile time if a certain template function was specialized?
With a function... I don't think so.
But if you create a functor, you can add a static const member (is_specialized, in the following example) that can give you this information
#include <iostream>
template <std::size_t N>
struct foo
{
static constexpr bool is_specialized { false };
void operator() () const
{ std::cout << "- generic (" << N << ") foo struct" << std::endl; }
};
template <>
struct foo<42U>
{
static constexpr bool is_specialized { true };
void operator() () const
{ std::cout << "- specialized (42) foo struct" << std::endl; }
};
int main()
{
foo<17U>()(); // print - generic (17) foo struct
foo<42U>()(); // print - specialized (42) foo struct
std::cout << foo<17U>::is_specialized << std::endl; // print 0
std::cout << foo<42U>::is_specialized << std::endl; // print 1
}
--- EDIT ---
Following the suggestion from Quentin (thanks again!) I've developed another functor-based solution that use something, to detect if the functor is generic or specialize, that is added only in the generic functor. In this case, a type instead a bool constant.
template <std::size_t N>
struct foo
{
// im_not_specialized is added only in the generic version!
using im_not_specialized = void;
void operator () () const
{ std::cout << "- generic (" << N << ") foo struct" << std::endl; }
};
template <>
struct foo<42U>
{
void operator () () const
{ std::cout << "- specialized (42) foo struct" << std::endl; }
};
This type can be used via SFINAE and I propose an example based on a constexpr isSpecialized() template function (with an helper function)
template <typename F>
constexpr bool isSpecializedHelper
(int, typename F::im_not_specialized const * = nullptr)
{ return false; }
template <typename F>
constexpr bool isSpecializedHelper (long)
{ return true; }
template <typename F>
constexpr bool isSpecialized ()
{ return isSpecializedHelper<F>(0); }
This require a little more work but isSpecialized() can be reused with different functors (im_not_specialized type based)
The following is a full working example
#include <iostream>
template <std::size_t N>
struct foo
{
// im_not_specialized is added only in the generic version!
using im_not_specialized = void;
void operator () () const
{ std::cout << "- generic (" << N << ") foo struct" << std::endl; }
};
template <>
struct foo<42U>
{
void operator () () const
{ std::cout << "- specialized (42) foo struct" << std::endl; }
};
template <typename F>
constexpr bool isSpecializedHelper
(int, typename F::im_not_specialized const * = nullptr)
{ return false; }
template <typename F>
constexpr bool isSpecializedHelper (long)
{ return true; }
template <typename F>
constexpr bool isSpecialized ()
{ return isSpecializedHelper<F>(0); }
int main()
{
foo<17U>()(); // print - generic (17) foo struct
foo<42U>()(); // print - specialized (42) foo struct
constexpr auto isSp17 = isSpecialized<foo<17U>>();
constexpr auto isSp42 = isSpecialized<foo<42U>>();
std::cout << isSp17 << std::endl; // print 0
std::cout << isSp42 << std::endl; // print 1
}
If you mark the base function as deleted (= delete), you can detect if it has been specialized using SFINAE (assuming the specialization itself is not deleted)
An expression like decltype(foo<N>()) will result in a substitution failure if foo<N> is marked as deleted. If you provide a specialization that is not deleted on the other hand the expression will not result in an error.
Using this you can create a simple trait class to check if foo has been specialized for a specific set of template parameters:
template<std::size_t N, class = void>
struct is_foo_specialized : std::false_type {};
template<std::size_t N>
struct is_foo_specialized<N, decltype(foo<N>(), void())> : std::true_type {};
1. Basic examples
C++11: godbolt
#include <type_traits>
template<std::size_t N>
void foo() = delete;
template<>
void foo<1>() { }
template<std::size_t N, class = void>
struct is_foo_specialized : std::false_type {};
template<std::size_t N>
struct is_foo_specialized<N, decltype(foo<N>(), void())> : std::true_type {};
int main()
{
static_assert(!is_foo_specialized<0>::value, ""); // foo<0> is not specialized
static_assert(is_foo_specialized<1>::value, ""); // foo<1> IS specialized
}
With C++20 you could also use a concept for this, e.g.: godbolt
#include <type_traits>
template<std::size_t N>
void foo() = delete;
template<>
void foo<1>() { }
template<std::size_t N>
concept is_foo_specialized = requires { foo<N>(); };
int main()
{
static_assert(!is_foo_specialized<0>); // foo<0> is not specialized
static_assert(is_foo_specialized<1>); // foo<1> IS specialized
}
2. Providing a default implementation
Due to the function being = delete'd it can't have a default implementation.
If you do require a default implementation for the function, you could use 2 functions instead:
one that is = delete'd (so SFINAE can detect it)
and another one that implements the default behaviour and forwards to the other if a specialization exists
C++11: godbolt
#include <type_traits>
#include <iostream>
template<std::size_t N>
void foo_specialized() = delete;
template<>
void foo_specialized<1>() { std::cout << "CUSTOMIZED!" << std::endl; }
template<std::size_t N, class = void>
struct is_foo_specialized : std::false_type {};
template<std::size_t N>
struct is_foo_specialized<N, decltype(foo_specialized<N>(), void())> : std::true_type {};
template<std::size_t N>
typename std::enable_if<!is_foo_specialized<N>::value>::type foo() {
std::cout << "DEFAULT!" << std::endl;
}
template<std::size_t N>
typename std::enable_if<is_foo_specialized<N>::value>::type foo() {
foo_specialized<N>();
}
int main()
{
foo<0>(); // -> DEFAULT!
foo<1>(); // -> CUSTOMIZED!
}
Or with C++20: godbolt
#include <type_traits>
#include <iostream>
template<std::size_t N>
void foo_specialize() = delete;
template<>
void foo_specialize<1>() { std::cout << "CUSTOMIZED!" << std::endl; }
template<std::size_t N>
concept is_foo_specialized = requires { foo_specialize<N>(); };
template<std::size_t N> requires (!is_foo_specialized<N>)
void foo() {
std::cout << "DEFAULT!" << std::endl;
}
template<std::size_t N> requires (is_foo_specialized<N>)
void foo() {
foo_specialize<N>();
}
int main()
{
foo<0>(); // -> DEFAULT!
foo<1>(); // -> CUSTOMIZED!
}
3. Compile-time shenanigans
This can of course also be used to iterate the specializations (within a certain limit) - or like you asked in the comments to find the nearest specialization of the function.
nearest_foo_specialized in this example will iterate over a range of values for N and check if a specialization of foo exists for this value.
N is the value where we want to start the search
SearchRange determines how many specializations will be checked (both up and down) from the provided N value (in this example we check for N's +/- 10)
CurrentDistance keeps track how far we've already searched from our starting N value, so we don't exceed the specified SearchRange
The last template parameter is used for SFINAE
e.g.:
nearest_foo_specialized<100, 10> would check for specializations of foo between N = 90 and N = 110, returning the one that is closer to 100 (prefering lower N values in case of a draw)
Example C++11: godbolt
#include <type_traits>
#include <iostream>
#include <utility>
template<std::size_t N>
void foo() = delete;
template<>
void foo<5>() { std::cout << 5 << std::endl; }
template<>
void foo<10>() { std::cout << 10 << std::endl; }
template<>
void foo<15>() { std::cout << 15 << std::endl; }
template<std::size_t N, class = void>
struct is_foo_specialized : std::false_type {};
template<std::size_t N>
struct is_foo_specialized<N, decltype(foo<N>(), void())> : std::true_type {};
template<std::size_t N, std::size_t SearchRange = 10, std::size_t CurrentDistance = 0, class = void>
struct nearest_foo_specialized {
static const std::size_t index = 0; // an index for which foo<> is specialized, if value is true.
static const std::size_t distance = CurrentDistance; // distance from original N
static const bool value = false; // have we found a specialization yet?
};
// Found a match -> Report Success
template<std::size_t N, std::size_t SearchRange, std::size_t CurrentDistance>
struct nearest_foo_specialized<N, SearchRange, CurrentDistance, typename std::enable_if< CurrentDistance <= SearchRange && is_foo_specialized<N>::value >::type> {
static const std::size_t index = N;
static const std::size_t distance = CurrentDistance;
static const bool value = true;
};
// No match found -> recurse until SearchRange limit
template<std::size_t N, std::size_t SearchRange, std::size_t CurrentDistance>
struct nearest_foo_specialized<N, SearchRange, CurrentDistance, typename std::enable_if< CurrentDistance < SearchRange && !is_foo_specialized<N>::value >::type> {
typedef nearest_foo_specialized<N - 1, SearchRange, CurrentDistance + 1> down;
typedef nearest_foo_specialized<N + 1, SearchRange, CurrentDistance + 1> up;
static const std::size_t distance = down::distance < up::distance ? down::distance : up::distance;
static const std::size_t index = down::distance == distance && down::value ? down::index : up::index;
static const std::size_t value = down::distance == distance && down::value ? down::value : up::value;
};
// calls the nearest foo() specialization (up to 10 away from the specified N)
template<std::size_t N>
typename std::enable_if<nearest_foo_specialized<N>::value>::type call_nearest_foo() {
foo<nearest_foo_specialized<N>::index>();
}
template<std::size_t N>
typename std::enable_if<!nearest_foo_specialized<N>::value>::type call_nearest_foo() {
static_assert(N!=N, "No nearest foo() specialization found!");
}
int main() {
call_nearest_foo<7>(); // calls foo<5>()
call_nearest_foo<8>(); // calls foo<10>()
call_nearest_foo<11>(); // calls foo<10>()
call_nearest_foo<15>(); // calls foo<15>()
call_nearest_foo<25>(); // calls foo<15>()
// call_nearest_foo<26>(); // error: No nearest foo() (only searching up to 10 up / down)
}

C++ constexpr values for types

I want to be able to create switch statements over a type's ID. I've found a mechanism that could give a unique ID for different types. It's very simple:
template <typename T>
struct type {
static void id() { }
};
template <typename T>
constexpr const size_t type_id() {
return reinterpret_cast<size_t>(&type<T>::id);
}
I thought this would evaluate to a constant that I could use as cases for the switch. But I get an error that the case expression is not a constant when I do the following:
int main(void) {
size_t a = type_id<int>();
switch (a) {
case type_id<int>():
break;
}
return 0;
}
Why is it not a constant? How could I achieve this effect?
Edit:
Can I do something like this without the reinterpret_cast then?
I'm not sure it's a good idea but... just for fun... using the constexpr counter, suggested in this page, you should be able to substitute the value of the pointer.
The following is a (I repeat: just for fun) full experiment
#include <iostream>
template <int N>
struct flag
{ friend constexpr int adl_flag (flag<N>); };
template <int N>
struct writer
{
friend constexpr int adl_flag (flag<N>)
{ return N; }
static constexpr int value { N };
};
template <int N, int = adl_flag (flag<N> {})>
int constexpr reader (int, flag<N>)
{ return N; }
template <int N>
int constexpr reader (float, flag<N>, int R = reader (0, flag<N-1> {}))
{ return R; }
int constexpr reader (float, flag<0>)
{ return 0; }
template <int N = 1>
int constexpr next (int R = writer<reader (0, flag<32> {}) + N>::value)
{ return R; }
template <typename T>
struct type
{
static constexpr int id { next() };
constexpr static int type_id ()
{ return id; }
};
void printType (int idT )
{
switch ( idT )
{
case type<int>::type_id():
std::cout << "- int type" << std::endl;
break;
case type<long>::id:
std::cout << "- long type" << std::endl;
break;
default:
std::cout << "- another type" << std::endl;
break;
}
}
int main ()
{
int ii { type<int>::id };
int il { type<long>::type_id() };
printType(ii);
printType(il);
}
I would like to suggest another approach which involves constexpr functions and macros (eeeewww...):
// Some naive text hashing function
template <std::size_t SIZE>
constexpr std::size_t hash(const char (&type_name)[SIZE])
{
std::size_t result{0xf};
for (const auto &c : type_name)
{
result <<= 1;
result |= c;
}
return result;
}
First we create a constexpr function able to transform a string literal into a number, this is my approach but you can choose anoter function as long as it is constexpr, then we create a macro which stringify the given parameter using the #:
#define TYPE_ID(X) hash(#X)
And now, we can use it:
int main(void) {
size_t a = TYPE_ID(int);
switch (a) {
case TYPE_ID(int):
break;
}
return 0;
}
Pros:
Pretty straightforward.
Tiny amount of code.
Cons:
Macros.
Accepts any value, included nonsense: TYPE_ID(I LOVE BACON) is valid.
Yields different result for TYPE_ID(size_t) and TYPE_ID(unsigned long) even if they might be the same type.
constexpr functions can not use reinterpret_cast in any shape or form. Some more formal reading can be found at http://en.cppreference.com/w/cpp/language/constant_expression
This may solve your problem:
#include <tuple>
//Index from http://stackoverflow.com/a/18063608/3484570
template <class T, class Tuple>
struct Index;
template <class T, class... Types>
struct Index<T, std::tuple<T, Types...>> {
static const std::size_t value = 0;
};
template <class T, class U, class... Types>
struct Index<T, std::tuple<U, Types...>> {
static const std::size_t value = 1 + Index<T, std::tuple<Types...>>::value;
};
template <class T>
constexpr std::size_t type_id() {
//need to add every type in this tuple:
return Index<T, std::tuple<int, double, char>>::value;
}
int main() {
size_t a = type_id<int>();
switch (a) {
case type_id<int>():
break;
}
}
The good news is that you get a type_id<T>() that you can use in a constexpr context such as in a case like you wanted.
The bad news is that you need to list all supported types.
In practice you might get used to the error message that occurs when you ask for the type_id of an unsupported type and just add it and eventually add all relevant types.

Associating an array with a variadic template

I'm now learning a little about templates and templates in C++11, C++14 and C++1z. I'm trying to write a variadic class template with an inside class that will associate an int to every template argument - and have a constexpr method that returns its array representation.
Let's say that I have ensured that the template cannot receive two of the same type as an argument. I was thinking about doing it somewhat like this:
template <typename... Types>
struct MyVariadicTemplate {
//we know that all types in Types... are different
template <int... Values>
struct MyInnerTemplate {
//I need to make sure that sizeof...(Values) == sizeof...(Types)
constexpr std::array<int, sizeof...(Values)> to_array() {
std::array<int, sizeof...(Values)> result = {Values...};
return result;
// this is only valid since C++14, as far as I know
}
};
};
this code should be valid (if it's not, I'd love to know why). Now, I'd like to add another inner template:
template <typedef Type>
struct AnotherInnerTemplate {};
that has a public typedef, which represents MyInnerTemplate with one on the position of Type in Types... and zeros elsewhere - and here I'm lost. I don't know how to proceed
I would appreciate any hint on how that can be done - and if I'm heading towards the wrong direction, I hope somebody can give me a hint on how to do that.
I think what you're looking for is something like this.
#include <array>
#include <cstddef>
#include <iostream>
#include <type_traits>
template <typename NeedleT, typename... HaystackTs>
constexpr auto get_type_index_mask() noexcept
{
constexpr auto N = sizeof...(HaystackTs);
return std::array<bool, N> {
(std::is_same<NeedleT, HaystackTs>::value)...
};
}
template <typename T, std::size_t N>
constexpr std::size_t ffs(const std::array<T, N>& array) noexcept
{
for (auto i = std::size_t {}; i < N; ++i)
{
if (array[i])
return i;
}
return N;
}
int
main()
{
const auto mask = get_type_index_mask<float, bool, int, float, double, char>();
for (const auto& bit : mask)
std::cout << bit;
std::cout << "\n";
std::cout << "float has index " << ffs(mask) << "\n";
}
Output:
00100
float has index 2
The magic happens in the parameter pack expansion
(std::is_same<NeedleT, HaystackTs>::value)...
where you test each type in HaystackTs against NeedleT. You might want to apply std::decay to either type if you want to consider, say, const int and int the same type.
template <int size, int... Values> struct AnotherImpl {
using Type = typename AnotherImpl<size - 1, Values..., 0>::Type;
};
template <int... Values> struct AnotherImpl<0, Values...> {
using Type = Inner<Values...>;
};
template <class T> struct Another {
using Type = typename AnotherImpl<sizeof...(Types) - 1, 1>::Type;
};
Full:
template <class... Types> struct My {
template <int... Values> struct Inner {
constexpr std::array<int, sizeof...(Values)> to_array() {
return std::array<int, sizeof...(Values)>{Values...};
}
};
template <int size, int... Values> struct AnotherImpl {
using Type = typename AnotherImpl<size - 1, Values..., 0>::Type;
};
template <int... Values> struct AnotherImpl<0, Values...> {
using Type = Inner<Values...>;
};
template <class T> struct Another {
using Type = typename AnotherImpl<sizeof...(Types) - 1, 1>::Type;
};
};
auto main() -> int {
My<int, float, char>::Another<int>::Type s;
auto a = s.to_array();
for (auto e : a) {
cout << e << " ";
}
cout << endl;
return 0;
}
prints:
1 0 0
Is this what you want?