How to specialize a template for 2 different values? - c++

Given the code below, I was wondering if it is possible to have a specialization for a set of values. In my example, I want to create an specialization for N=3 or N=4 to use an array of known size. Is it possible to avoid code duplication in this case?
template <typename T, unsigned int N>
class A
{
public:
T* data;
};
template <typename T>
class A<T, 3>
{
public:
T data[3];
};
template <typename T>
class A<T, 4>
{
public:
T data[4];
};
int main()
{
A<int, 1> u;
std::cout << sizeof(u.data) << std::endl; // Size of pointer
A<int, 3> v;
std::cout << sizeof(v.data) << std::endl; // Size of data
A<int, 4> w;
std::cout << sizeof(w.data) << std::endl; // Size of data
return 0;
}

You can use std::enable_if by introducing a default void template parameter in the general case.
template <typename T, unsigned int N, typename = void>
class A
{
public:
T* data;
};
template <typename T, unsigned int N>
class A<T, N, typename std::enable_if<N == 3 || N == 4>::type>
{
public:
T data[N];
};
live wandbox example
If N == 3 || N == 4 is true, then typename std::enable_if<N == 3 || N == 4>::type is well-formed and evaluates to void. The specialization is then chosen.
If N == 3 || N == 4 is false, then typename std::enable_if<N == 3 || N == 4>::type is ill-formed and the specialization is "SFINAEd away". The general case is then chosen.

Related

Represents empty type in C++ class template

consider the following example of a compile-time "vector".
#include <iostream>
template <int n, int...ns>
struct static_vector {
static constexpr int value = n;
static_vector<ns...> rest;
};
template <int n>
struct static_vector<n> {
static constexpr int value = n;
void* rest;
};
template <int n, class sv>
constexpr int access_nth() {
static_assert(n >= 0, "vector size out of bound");
if constexpr(n == 0) {
return sv::value;
} else {
static_assert(!std::is_same_v<decltype(sv::rest), void *>, "vector size out of bound");
return access_nth<n-1, decltype(sv::rest)>();
}
}
int main()
{
constexpr auto a = static_vector<12, 23, 34, 45>();
constexpr int nth = access_nth<5, decltype(a)>();
std::cout << nth << std::endl;
}
I am mostly satisfied with what we can do now: define a vector and then get the nth element out of it. The one thing I found that not satisfying is this: I have to use void * as a dummy in the base case (where the vector only holds one element and no tail...)
I tried to have a specialisation like this:
template <>
struct static_vector<> {
}
to represent the empty vector. But it seems that the compiler always rejects this definition with the following error:
<source>:16:8: error: too few template arguments for class template 'static_vector'
struct static_vector<> {
^
What should I do here so I can have an empty vector?
Thanks a lot.
But why recursion ?
You tagged C++17 so you can use template folding, so... what about as follows ?
#include <iostream>
template <int ... Is>
struct static_vector
{
template <std::size_t N>
int get () const
{
static_assert( N < sizeof...(Is), "index out of bound" );
std::size_t i{};
int ret;
( ... , (N == i++ ? ret = Is : 0) );
return ret;
}
};
int main()
{
constexpr auto a = static_vector<12, 23, 34, 45>();
std::cout << a.get<3u>() << std::endl;
}
Specializations must conform to the base template declaration. Since at least one int is required by the base template, this does not compile.
You can make this work by declaring the template to take any number of int arguments, then specializing every case that takes one or more arguments. The base declaration is then the empty case:
template <int...>
struct static_vector {
// Instantiated only for the no-argument case
};
template <int n>
struct static_vector<n> {
// One-argument specialization
};
template <int n, int... ns>
struct static_vector<n, ns...> {
// Two-or-more-argument specialization
};

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?

Specializing a function from a variadic template class

Consider this illegal code:
template <int... Is>
struct Object {
void foo() const;
};
template <int... Js>
void Object<0, Js...>::foo() {/*Do whatever*/}
We want to specialize foo() when the first template parameter is 0, and let's say we want to specialize foo() as well if the second parameter is 3, and the third int is 1. So the solution I found (not sure if its the best approach) is the following:
#include <iostream>
template <int...> struct Foo;
template <int... Is>
struct Object {
int ID; // This member is just to illustrate the case when 'this' is needed in foo().
friend struct Foo<Is...>;
void foo() const {Foo<Is...>::execute(this);} // Pass 'this' in case it is needed.
};
template <int... Is>
struct Foo<0, Is...> {
static void execute (const Object<0, Is...>* object) {std::cout << "First int = 0, ID = " << object->ID << ".\n";}
};
template <int N, int... Is>
struct Foo<N, 3, Is...> {
static void execute (const Object<N, 3, Is...>* object) {std::cout << "Second int = 3, ID = " << object->ID << ".\n";}
};
template <int M, int N, int... Is>
struct Foo<M, N, 1, Is...> {
static void execute (const Object<M, N, 1, Is...>* object) {std::cout << "Third int = 1, ID = " << object->ID << ".\n";}
};
int main() {
Object<0,5,8,2>{4}.foo();
Object<4,3,2,5,3>{2}.foo();
Object<4,2,1>{0}.foo();
}
First of all, is this solution any good? Next, the problem now arises if we try Object<0,3,1,4>{8}.foo(); because the spec was not complete. So let's say that the earliest matched specialized int will always take precedence. So in this case Object<0,3,1,4>{8}.foo(); should run the first specialization because of the 0, while Object<9,3,1,4>{8}.foo(); shall run the second specialization because of the 3, and so forth. How to enforce that rule?
I suggest just using if statements. The compiler will probably optimize them away anyway (assuming you have optimization enabled).
In other words, just do something like this:
template <int... Js>
void Object::foo() {
std::array<int, sizeof...(Js)> args = {Js...}; // I _think_ this is the correct syntax to dump the parameter pack into an std::array.
if(args.size() > 0 && args[0] == 0) {
// First argument is 0, do whatever.
} else {
// It's not 0, do your other thing.
}
}
You'll get pretty much the same effect, and your code will be quite a bit clearer.
A comment and a hint.
The approach for me is OK. Since we do not have partial template specialization for functions that's all we have.
Then regarding Object<0,3,1,4>{8}.foo() this gives ambiguous partial specializations (on Clang 3.6). To solver this problem I ended up adding another partial specialization
template <int... Is>
struct Foo<0, 3, Is...> {
static void execute (const Object<0, 3, Is...>* object) {std::cout << "First int = 0, second = 3, ID = " << object->ID << ".\n";}
};
Another possibility is mess with std::integer_sequence. I have to give up now, the following is not a solution, just an appetizer...
#include <utility>
#include <iostream>
template <class S1, class S2>
struct seq_lt
{
enum {value = 0} ;
} ;
template <int I1, int ...S1, int I2, int ...S2>
struct seq_lt<std::integer_sequence<int, I1, S1...>,
std::integer_sequence<int, I2, S2...>>
{
enum {value = (I1 < I2 ? 1 : 0)} ;
} ;
int main(int argc, char *argv[])
{
std::integer_sequence<int, 1, 2, 3> seq1 ;
std::integer_sequence<int, 2, 3> seq2 ;
std::cout << "seq_lt " << seq_lt<decltype(seq1), decltype(seq2)>::value << std::endl ;
std::cout << "seq_lt " << seq_lt<decltype(seq2), decltype(seq1)>::value << std::endl ;
}
This solution was inspired by Marom's second suggestion, and also inspired partly by celticminstrel's solution too.
#include <iostream>
#include <type_traits>
template <std::size_t, typename T, T...> struct NthValue;
template <typename T, T First, T... Rest>
struct NthValue<0, T, First, Rest...> : std::integral_constant<T, First> {};
template <std::size_t N, typename T, T First, T... Rest>
struct NthValue<N, T, First, Rest...> : NthValue<N - 1, T, Rest...> {};
template <int... Is>
struct Object {
void foo() const {fooHelper (typename Map<Is...>::type{});}
private:
template <int...> struct Map;
template <int, int> struct MappedType {};
struct Default {};
void fooHelper (const MappedType<0,0>&) const {std::cout << "First int = 0.\n";}
void fooHelper (const MappedType<1,3>&) const {std::cout << "Second int = 3.\n";}
void fooHelper (const MappedType<2,1>&) const {std::cout << "Third int = 1.\n";}
void fooHelper (const Default&) const {std::cout << "Default case.\n";}
};
template <int... Ns>
template <int... Is>
struct Object<Ns...>::Map {
using type = typename std::conditional<NthValue<0, int, Is...>::value == 0,
MappedType<0,0>,
typename std::conditional<NthValue<1, int, Is...>::value == 3,
MappedType<1,3>,
typename std::conditional<NthValue<2, int, Is...>::value == 1,
MappedType<2,1>,
Default
>::type
>::type
>::type;
};
int main() {
Object<0,5,8,2>().foo(); // First int = 0.
Object<4,3,2,5,3>().foo(); // Second int = 3.
Object<4,2,1>().foo(); // Third int = 1.
Object<0,3,1,4>().foo(); // First int = 0.
Object<9,3,1,4>().foo(); // Second int = 3.
Object<9,9,9>().foo(); // Default case.
}
There is also no run-time overhead.

Creating an instance of a specialized class depending on run-time arguments

Here's the code which demonstrates the idea:
struct A
{
};
struct B
{
};
template<typename T1, typename T2>
struct Specific
{
T1 t1;
T2 t2;
void DoSomething() {}
};
template<typename T1, typename T2>
Specific<T1, T2> create_specific()
{
return Specific<T1, T2>();
}
void my_func(int type1, int type2)
{
if (type1 == 1 && type2 == 1)
{
auto specific = create_specific<A, A>();
specific.DoSomething();
}
else if (type1 == 1 && type2 == 2)
{
auto specific = create_specific<A, B>();
specific.DoSomething();
}
else if (type1 == 2 && type2 == 1)
{
auto specific = create_specific<B, A>();
specific.DoSomething();
}
else if (type1 == 2 && type2 == 2)
{
auto specific = create_specific<B, B>();
specific.DoSomething();
}
}
So my_func arguments control which type it will use to DoSomething.
The problem with this approach is that the number of if conditions will grow exponentially. I'm looking for a way to have the compiler do this for me. It would be nice if I could split the logic for every type slot:
if (type1 == 1)
{
create_specific1<A>(...);
}
....
if (type2 == 2)
{
create_specific2<B>(...);
}
Is it at all possible?
UPDATE
Is there any way to implement the template magic in C++11, in particular in Visual C++ 2013?
One way is to use a lookup table like this.
void (*arr[2][2])() =
{
[] { create_specific<A, A>().DoSomething(); },
[] { create_specific<A, B>().DoSomething(); },
[] { create_specific<B, A>().DoSomething(); },
[] { create_specific<B, B>().DoSomething(); }
};
arr[type1-1][type2-1]();
You can also let the compiler produce it for you. This works with two types:
template <std::size_t...> struct index_list {using type = index_list;};
template <typename, typename> struct concat;
template <std::size_t... i, std::size_t... j> struct concat<index_list<i...>, index_list<j...>> : index_list<i..., j...> {};
// inefficient linear recursive method:
template <std::size_t N>
struct make_index_list : concat<typename make_index_list<N-1>::type, index_list<N>> {};
template <>
struct make_index_list<0> : index_list<0> {};
template <typename A, typename B = A,
typename = typename make_index_list<std::tuple_size<A>::value
* std::tuple_size<B>::value - 1>::type>
class create_lookup;
template <typename ... First, typename... Second, std::size_t... indices>
class create_lookup<std::tuple<First...>, std::tuple<Second...>, index_list<indices...>>
{
template <typename T, typename U>
static void work()
{
create_specific<T, U>().DoSomething();
}
public:
static constexpr void (*arr[sizeof...(First)][sizeof...(Second)])() =
{
work< typename std::tuple_element<indices / sizeof...(First), std::tuple<First...>>::type,
typename std::tuple_element<indices % sizeof...(Second), std::tuple<Second...>>::type >...
};
};
template <typename ... F, typename... S, std::size_t... I>
constexpr void (*create_lookup<std::tuple<F...>, std::tuple<S...>, index_list<I...>>::arr[sizeof...(F)][sizeof...(S)])();
int main()
{
auto arr = create_lookup<std::tuple<A, B>>::arr;
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
{
std::cout << i << ' ' << j << ": ";
arr[i][j]();
}
}
Since C++14 you could also use a lambda as the expansion pattern, instead of a function template (work). And std::make_index_sequence, and std::tuple_element_t ... ;)
Setting the DoSomething-function to
void DoSomething()
{
std::cout << typeid(T1).name() << ' ' << typeid(T2).name() << '\n';
}
yields the following output:
0 0: A A
0 1: A B
1 0: B A
1 1: B B
Generazalization to more types
This code works with an arbitrary amount of concatenations, specified by the template parameter depth. Example is included, using GCC's demangle function.
#include <iostream>
#include <iomanip>
#include <typeinfo>
#include <tuple>
#include <cxxabi.h>
template<typename... T>
struct Specific
{
void DoSomething()
{
int status;
std::initializer_list<bool> { std::cout << abi::__cxa_demangle(typeid(T).name(), 0, 0, &status) << ' '... };
//std::initializer_list<bool> { std::cout << typeid(T).name() << ' '... };
std::cout << '\n';
}
};
template<typename... T>
Specific<T...> create_specific()
{ return {}; }
template <std::size_t...> struct index_list {using type = index_list;};
template <typename, typename> struct concat;
template <std::size_t... i, std::size_t... j> struct concat<index_list<i...>, index_list<j...>> : index_list<i..., j...> {};
template <std::size_t N>
struct make_index_list : concat<typename make_index_list<N-1>::type, index_list<N>> {};
template <>
struct make_index_list<0> : index_list<0> {};
constexpr std::uintmax_t ipow( std::uintmax_t base, unsigned exp )
{
return exp == 0? 1 : base*ipow(base, exp-1);
}
template <typename T, std::size_t len, std::size_t dim>
struct construct_array
{
using type = typename construct_array<T, len, dim-1>::type[len];
};
template <typename T, std::size_t len>
struct construct_array<T, len, 1>
{
using type = T[len];
};
template <std::size_t depth,
typename A,
typename = typename make_index_list<ipow(std::tuple_size<A>::value, depth)- 1>::type>
class create_lookup;
template <std::size_t depth, typename ... First, std::size_t... indices>
class create_lookup<depth, std::tuple<First...>, index_list<indices...>>
{
template <typename... Args>
static void work()
{
create_specific<Args...>().DoSomething();
}
static constexpr auto length = sizeof...(First);
template <std::size_t index, typename = typename make_index_list<depth-1>::type>
struct get_ptr;
template <std::size_t index, std::size_t ... type_indices>
struct get_ptr<index, index_list<type_indices...>>
{
static constexpr auto value =
work< typename std::tuple_element<index / ipow(length, depth-type_indices-1) % length, std::tuple<First...>>::type... >;
};
public:
static constexpr typename construct_array<void(*)(), length, depth>::type arr
{
get_ptr<indices>::value...
};
};
template <std::size_t depth, typename ... F, std::size_t... I>
constexpr typename construct_array<void(*)(), create_lookup<depth, std::tuple<F...>, index_list<I...>>::length, depth>::type
create_lookup<depth, std::tuple<F...>, index_list<I...>>::arr;
struct A {};
struct B {};
struct C {};
int main()
{
auto arr = create_lookup<3, std::tuple<A, B, C>>::arr;
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
for (int k = 0; k < 3; ++k)
{
std::cout << i << ' ' << j << ' ' << k << ": ";
arr[i][j][k]();
}
}
The same code but without constexpr can be found here.

Unrolling loops using templates in C++ with partial specialization

I'm trying to use templates to unroll a loop in C++ as follows.
#include <iostream>
template< class T, T i >
struct printDown {
static void run(void) {
std::cout << i << "\n";
printDown< T, i - 1 >::run();
}
};
template< class T >
struct printDown< T, 0 > {
static void run(void) {
std::cout << 0 << "\n";
}
};
int main(void) {
printDown< int, 10 >::run();
return 0;
}
When I compile w/ g++ 3.4.4 in Cygwin, I get the following error.
tmp.cpp:12: error: type T' of
template argument0' depends on
template parameter(s)
What am I doing wrong? Do I need to somehow annotate the 0 to say that it's of type T?
Thanks in advance.
Have you tried int i instead of T i?
Why this happens? From 14.5.5/8,
— The type of a template parameter
corresponding to a specialized
non-type argument shall not be
dependent on a parameter of the
specialization. [ Example:
template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error
template< int X, int (*array_ptr)[X] > class A {};
int array[5];
template< int X > class A<X,&array> { }; // error
—end example ]
Therefore when you apply partial specialization, the type of 0 is T (dependent on a parameter of the specialization). There are two choices, one is to make it none dependent, e.g., change T i to int i, and second is to apply explicit specialization rather than partial specialization.
Both solutions have been given out by others, so I'm not gonna to repost them here. At least you know the reason. It's defined by standard.
As pointed out by phooji your implementation suffers from a small issue: it quickly generates a long list of calls, which will make compilers choke quickly.
You could work around this by implementing a slightly more complicated version, using binary decomposition. I'll make it generic on a functor too, cause I am lazy.
// Signature
template <Functor F, unsigned N>
struct UnrolledLoop;
We need a helper template, which keeps an offset of the parameter to pass
template <Functor F, unsigned N, unsigned OffSet>
struct UnrolledImpl;
template <Functor F, unsigned OffSet>
struct UnrolledImpl<F, 0, OffSet>
{
static F run(F f) { return f; }
};
template <Functor F, unsigned OffSet>
struct UnrolledImpl<F, 1, OffSet>
{
static F run(F f) { f(OffSet); return f; }
};
template <Functor F, unsigned N, unsigned OffSet>
struct UnrolledImpl
{
static F run(F f) {
F f2 = UnrolledImpl<F, N/2, OffSet>::run(f);
return UnrolledImpl<F, N - N/2, OffSet + N/2>::run(f2);
}
};
And you can implement UnrolledLoop simply:
template <Functor F, unsigned N>
struct UnrolledLoop
{
static F run(F f) { return UnrolledImpl<F, N, 0>::run(f); }
}
Note that you could provide specialization for more values of N (3, 4 for example) to be nicer on the compiler.
What about adding this to your example:
template struct printDown< int, 0 >{
static void run(void) {
std::cout << 0 << "\n";
} };
The compiler cannot cast 0 to int automatically without knowing T's type in advance.
Just found this out. Apparently one can do something like this.
template< class T, T i, bool b = (i == 0) >
struct printDown {
static void run(void) {
std::cout << i << "\n";
printDown< T, i - 1 >::run();
}
};
template< class T, T i >
struct printDown< T, i, true > {
static void run(void) {
std::cout << 0 << "\n";
}
};
I had no idea that could be done. Very Prologish & very nice.
You can make the parameter a type parameter to work this around
template< bool > struct bool_ { };
template< class T, T i, typename = bool_<true> >
struct printDown {
static void run(void) {
std::cout << i << "\n";
printDown< T, i - 1 >::run();
}
};
template< class T, T i >
struct printDown< T, i, bool_<i == 0> > {
static void run(void) {
std::cout << 0 << "\n";
}
};
int main(void) {
printDown< int, 10 >::run();
return 0;
}
This way you can specify any conditions you want in the partial specializations.