I have two enums
#include <iostream>
enum class E1 : unsigned int
{
E11 = 1
};
enum class E2 : unsigned int
{
E21 = 1
};
which have identical underlying values (1) in this case. Next, I have a class C which has two template parameters, an integer j and a value i with type auto.
template<int j, auto i>
struct C
{ C() { std::cout << "none\n"; } };
I want to partially specialize this class for both E1::E11 and E2::E21 like this:
template<int j>
struct C<j, E1::E11>
{ C() { std::cout << j << "E11\n"; } };
template<int j>
struct C<j, E2::E21>
{ C() { std::cout << j << "E21\n"; } };
And for completeness sake here is main that instantiates two objects:
int main()
{
C<0,E1::E11> e11;
C<1,E2::E21> e21;
return 0;
}
The code above works absolutely fine on gcc and icc as can be verified on Godbolt (full code)
But it fails with any other compiler (clang, msvc). With the following message
<source>:27:18: error: ambiguous partial specializations of 'C<0, E1::E11>'
C<0,E1::E11> e11;
^
<source>:18:8: note: partial specialization matches [with j = 0]
struct C<j, E1::E11>
^
<source>:22:8: note: partial specialization matches [with j = 0]
struct C<j, E2::E21>
It's kind of clear to me why this happens. The question that I can't seem to answer though is whether it is possible to solve this in a standard compatible way (if this is some gcc or icc feature) or if there's a workaround for the failing compilers (clang, msvc).
Btw. if I remove the int j template argument and just leave the auto i the code compiles with all compilers.
Thanks in advance,
Arno
The auto template argument can be replaced by
template<int j,typename T,T i>
struct C
{ C() { std::cout << "none\n"; } };
If you are fine with more typing you can explicitly specify the type of the enum:
#include <iostream>
enum class E1 : unsigned int
{
E11 = 1
};
enum class E2 : unsigned int
{
E21 = 1
};
template<int j,typename T,T i>
struct C
{ C() { std::cout << "none\n"; } };
template<int j>
struct C<j,E1, E1::E11>
{ C() { std::cout << j << "E11\n"; } };
template<int j>
struct C<j,E2, E2::E21>
{ C() { std::cout << j << "E21\n"; } };
int main()
{
C<0,E1,E1::E11> e11;
C<1,E2,E2::E21> e21;
return 0;
}
And for less typing you can use a helper function:
template <int j,auto i>
auto make_C(){
return C<j,decltype(i),i>();
}
int main()
{
auto e11 = make_C<0,E1::E11>();
auto e21 = make_C<1,E2::E21>();
}
... or a type trait:
template <int j,auto i>
struct C_helper {
using type = C<j,decltype(i),i>;
};
int main()
{
C_helper<0,E1::E11>::type e11;
C_helper<1,E2::E21>::type e21;
}
msvc/clang seems to have issue with partial specialization in your cases :(
As workaround, you might split the parameter in 2 classes:
template <auto i>
struct EC
{
template <int j>
struct C
{
C() { std::cout << "none\n"; }
};
};
template <>
struct EC<E1::E11>
{
template <int j>
struct C
{
C() { std::cout << j << "E11\n"; }
};
};
// Same for E2::E21
and then
EC<E1::E11>::C<0> e11;
EC<E2::E21>::C<0> e21;
Demo
Related
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)
}
Below I am trying to get a simple max value from a list of traits containing SOME_VAL at compile time:
struct A_Traits { enum { SOME_VAL=5 }; };
struct B_Traits { enum { SOME_VAL=6 }; };
struct C_Traits { enum { SOME_VAL=4 }; };
template<typename T>
T MAX(T t1, T t2)
{
return t1>t2?t1:t2;
}
template<typename T, typename... Args>
struct max_calculator
{
enum { MAX_VAL = MAX(max_calculator<typename T::SOME_VAL>::MAX_VAL, // line 65
max_calculator<Args...>::MAX_VAL) };
};
template<typename T>
struct max_calculator<T>
{
enum { MAX_VAL = T::SOME_VAL };
};
int main()
{
cout << max_calculator<A_Traits>::MAX_VAL << endl;
cout << max_calculator<A_Traits, B_Traits>::MAX_VAL << endl; // line 79
}
However I get a compile error of:
variadic.cpp: In instantiation of 'struct max_calculator<A_Traits, B_Traits>':
variadic.cpp:79:47: required from here
variadic.cpp:65:10: error: no type named 'SOME_VAL' in 'struct A_Traits'
Any idea whats wrong or better ideas to do the same at compile time?
std::max has a constexpr overload for std::initialiser_list<T>, you can expand your pack in one place
template<typename... Args>
struct max_calculator
{
enum { MAX_VAL = std::max({ Args::SOME_VAL... }) };
};
For the benefit of everyone visting this later - the fixed program based on Piotr's answers in the comments section is:
struct A_Traits { enum { SOME_VAL=5 }; };
struct B_Traits { enum { SOME_VAL=6 }; };
struct C_Traits { enum { SOME_VAL=4 }; };
template<typename T>
constexpr T MAX(T t1, T t2)
{
return t1>t2?t1:t2;
}
template<typename T, typename... Args>
struct max_calculator
{
enum { MAX_VAL =MAX<uint8_t>(max_calculator<T>::MAX_VAL,
max_calculator<Args...>::MAX_VAL) };
};
template<typename T>
struct max_calculator<T>
{
enum { MAX_VAL = T::SOME_VAL };
};
int main()
{
cout << max_calculator<A_Traits>::MAX_VAL << endl;
cout << max_calculator<A_Traits, B_Traits>::MAX_VAL << endl;
cout << max_calculator<A_Traits, B_Traits, C_Traits>::MAX_VAL << endl;
}
I would like to do something like this:
#include <iostream>
class a {
public:
a() : i(2) {}
template <typename ...ts>
void exec() {
f<ts...>();
std::cout << "a::()" << std::endl;
}
int i;
private:
template <typename t>
void f() {
i += t::i;
}
template <typename t, typename ...ts>
void f() {
f<t>();
f<t, ts...>();
}
};
struct b {
static const int i = -9;
};
struct c {
static const int i = 4;
};
int main()
{
a _a;
_a.exec<b,c>();
std::cout << _a.i << std::endl;
}
The idea is to get the same information from a group of classes, without the need of an object of each class.
Does anyone know if it is possible?
Thanks!
In case Your compiler does not support C++17:
template <typename ...ts>
void f() {
for ( const auto &j : { ts::i... } )
i += j;
}
In C++17, your class would simply be
class a {
public:
a() : i(2) {}
template <typename ...ts>
void exec() {
((i += ts::i), ...); // Folding expression // C++17
std::cout << "a::()" << std::endl;
}
int i;
};
Possible in C++11 too, but more verbose.
Reasons why your code is not compiling:
Syntax of specializing templates is a little different.
You need to put the most general case first.
You can't partially specialize functions, only classes.
Partial specialization is not allowed within classes, only in namespaces.
Here is an example for C++11.
#include <iostream>
template<typename t, typename ...ts>
class a {
public:
static constexpr int x = t::i + a<ts...>::x;
};
template<typename t>
class a<t> {
public:
static constexpr int x = 2 + t::i;
};
struct b {
static constexpr int i = -9;
};
struct c {
static constexpr int i = 4;
};
int main()
{
constexpr int result = a<b,c>::x;
std::cout << result << std::endl;
}
Remember that templates are calculated during compilation so, for optimization sake, it is a good idea to write them in a way that allows them to be constexpr.
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)
}
I've this situation:
class A {
...
};
class B {
public:
B(A x) { .... }
}
std::array<A, some_constant_value> init;
std::array<B, some_constant_value> arr = {
init[0],
init[1],
init[2],
...... ,
init[some_constant_value-1]
};
Is there, by any chance, a better syntax than this to avoid typing all the elements down? ( And that won't require meddling in the off-chance that some_constant_value will change? )
I have this code lying around. I think it's what you want:
template<unsigned... Indices>
struct indices {
using next = indices<Indices..., sizeof...(Indices)>;
};
template<unsigned N>
struct build_indices {
using type = typename build_indices<N-1>::type::next;
};
template<>
struct build_indices<0> {
using type = indices<>;
};
namespace impl {
template<typename To, typename From, unsigned... Is>
std::array<To, sizeof...(Is)>
array_convert_impl(std::array<From, sizeof...(Is)> const& from, indices<Is...>) {
return std::array<To, sizeof...(Is)>{{ from[Is]... }};
}
} // namespace impl
template<typename To, typename From, unsigned N>
std::array<To, N>
array_convert(std::array<From, N> const& from) {
return impl::array_convert_impl<To>(from, typename build_indices<N>::type());
}
Then you can do:
std::array<B, some_constant_value> arr = array_convert<B>(init);
An alternative solution provided by the Standard Library is:
std::array<B, some_constant_value>
arr((std::copy(init.begin(),init.end(),(&arr)->begin()),arr));
Note that the argument of the constructor is enclosed by ((...)), so that it
is correctly parsed as a comma-expression rather than as two arguments.
This solution relies upon the fact that B is implicitly constructible from
A. A short solution that will also work if the converting constructor is
made explicit is:
auto lamb =
[&init]() -> B { static size_t i = 0; return B(init[i++]); };
std::array<B, some_constant_value>
arr((std::generate((&arr)->begin(),(&arr)->end(),lamb),arr));
The following test program, built with GCC 4.7.2, clang 3.2 and Intel C++ 13.1.1,
(options -g -O0 -Wall -std=c++11) illustrates both solutions:
#include <iostream>
#include <array>
#include <algorithm>
struct A
{
int _i = 42;
};
struct B
{
B(A x)
: _i(x._i){}
int _i;
};
struct C
{
explicit C(A x)
: _i(x._i){}
int _i;
};
using namespace std;
int main()
{
array<A, 10> init;
array<B, 10> arr((copy(init.begin(),init.end(),(&arr)->begin()),arr));
cout << "arr contains..." << endl;
for (size_t i = 0; i < arr.size(); ++i) {
cout << arr[i]._i << endl;
}
auto lamb =
[&init]() -> C { static size_t i = 0; return C(init[i++]); };
array<C, 10> brr((generate((&brr)->begin(),(&brr)->end(),lamb),brr));
cout << "brr contains..." << endl;
for (size_t i = 0; i < brr.size(); ++i) {
cout << brr[i]._i << endl;
}
return 0;
}