I think I will first show the example and then explain it:
#include <array>
template<typename T_, size_t size_>
struct arg
{
using T = T_;
static constexpr size_t size = size_;
};
template<typename... Arugments>
struct Foo
{
template<typename Argument>
std::array<typename Argument::T, Argument::size>& getArray() // specializations of all args in Arguments should be generated
{
static std::array<typename Argument::T, Argument::size> arr;
return arr;
}
};
int main()
{
Foo<arg<int, 10>, arg<float, 10>, arg<float, 1>> myFoo;
myFoo.getArray<arg<int, 10>>();
myFoo.getArray<arg<float, 10>>(); // should return a different array than the line above
myFoo.getArray<arg<bool, 1>>(); // should NOT work because arg<bool, 10> is was not passed to Foo
}
If got a struct arg
which contains the information how to construct arr
in getArray
. A list of args is passed to Foo
. Now I want that template specializations of getArray
to be generated for each arg
in Arguments
. If no specialization was generated for a specific arg
I want that some kind of error occurs.
How could I achieve this?
You can use static_assert
to make sure Argument
is part of Arguments
with a helper struct.
#include <array>
#include <iostream>
template <typename... T>
struct contains;
template <typename T>
struct contains<T> : std::false_type {};
template <typename T, typename U, typename... Rest>
struct contains<T, U, Rest...> : contains<T, Rest...> {};
template <typename T, typename... Rest>
struct contains<T, T, Rest...> : std::true_type {};
template<typename T_, std::size_t size_>
struct arg
{
using T = T_;
static constexpr std::size_t size = size_;
};
template<typename... Arguments>
struct Foo
{
template<typename Argument>
std::array<typename Argument::T, Argument::size>& getArray() // specializations of all args in Arguments should be generated
{
static_assert(contains<Argument, Arguments...>(), "Invalid type");
static std::array<typename Argument::T, Argument::size> arr;
return arr;
}
};
int main()
{
Foo<arg<int, 10>, arg<float, 10>, arg<float, 1>> myFoo;
myFoo.getArray<arg<int, 10>>()[5] = 7;
myFoo.getArray<arg<float, 10>>(); // should return a different array than the line above
//myFoo.getArray<arg<bool, 1>>(); // should NOT work because arg<bool, 10> is was not passed to Foo
Foo<arg<int, 10>, arg<float, 10>, arg<float, 1>> myFoo2;
std::cout << myFoo2.getArray<arg<int, 10>>()[5];
Foo<arg<int, 10>, arg<float, 10>, arg<double, 1>> myFoo3;
std::cout << myFoo3.getArray<arg<int, 10>>()[5];
}
Just wanted to also point out that as demonstrated by the code, myFoo
and myFoo2
returns the same array since they are the exact same type.
myFoo3
on the other hand is a separate type, which means the getArray
member function is a separate function and has it's own copy of the same type array.