Самый простой способ получить N-й аргумент вариационного шаблонного класса?
Интересно, что самый простой и распространенный способ получить N-й параметр вариационного шаблонного класса во время компиляции (возвращаемое значение должно быть как static const для компилятора чтобы сделать некоторые оптимизации). Вот форма моего шаблона:
template<unsigned int... T> MyClass
{
// Compile-time function to get the N-th value of the variadic template ?
};
Большое спасибо.
EDIT: поскольку MyClass будет содержать более 200 функций, я не могу его специализировать. Но я могу специализировать структуру или функцию внутри MyClass.
EDIT: окончательное решение, полученное из утвержденного ответа:
#include <iostream>
template<unsigned int... TN> class MyClass
{
// Helper
template<unsigned int index, unsigned int... remPack> struct getVal;
template<unsigned int index, unsigned int In, unsigned int... remPack> struct getVal<index, In,remPack...>
{
static const unsigned int val = getVal<index-1, remPack...>::val;
};
template<unsigned int In, unsigned int...remPack> struct getVal<1,In,remPack...>
{
static const unsigned int val = In;
};
// Compile-time validation test
public:
template<unsigned int T> inline void f() {std::cout<<"Hello, my value is "<<T<<std::endl;}
inline void ftest() {f<getVal<4,TN...>::val>();} // <- If this compile, all is OK at compile-time
};
int main()
{
MyClass<10, 11, 12, 13, 14> x;
x.ftest();
return 0;
}
Ответы
Ответ 1
Вот еще один способ сделать это:
template<unsigned int index, unsigned int In, unsigned int... remPack> struct getVal
{
static const unsigned int val = getVal<index-1, remPack...>::val;
};
template<unsigned int In, unsigned int...remPack> struct getVal<0,In,remPack...>
{
static const unsigned int val = In;
};
template<unsigned int... T> struct MyClass
{
//go to any arg by : getVal<Some_Unsigned_Index, T...>::val;
};
Тест: http://liveworkspace.org/code/4a1a9ed4edcf931373e7ab0bf098c847
и если вы получите sting с помощью "не может расширить" T... "в список аргументов фиксированной длины" http://ideone.com/YF4UJ
Ответ 2
"Дизайн по индукции" должен выглядеть примерно так:
template<unsigned int N, unsigned int Head, unsigned int... Tail>
struct GetNthTemplateArgument : GetNthTemplateArgument<N-1,Tail...>
{
};
template<unsigned int Head, unsigned int... Tail>
struct GetNthTemplateArgument<0,Head,Tail...>
{
static const unsigned int value = Head;
};
template<unsigned int... T>
class MyClass
{
static const unsigned int fifth = GetNthTemplateArgument<4,T...>::value;
};
Ответ 3
Вот что вы можете сделать и
template<int N, typename T, T ... Ts>
struct GetN {
constexpr T values[sizeof...(Ts)] = { Ts... };
static const T value = values[N];
};
template<int N, typename T, T ... Ts>
constexpt T GetN<N, T, Ts...>::values[sizeof...(Ts)];
Тогда вы можете просто сделать
template<int N, unsigned int... T> struct MyClass {
static const unsigned int value = GetN<N, unsigned int, T...>::value;
};
Ответ 4
Еще один простой способ:
#include <array>
template<int... Args>
class Foo {
public:
static constexpr int Element(int index) {
return std::array<int, sizeof...(Args)>{ Args... }[index];
}
int First = Element(0);
int Second = Element(1);
};
int main() {
return Foo<0, 1>::Element(0);
}
// or just
int Nth = std::array<int, sizeof...(Args)>{ Args... }[N];
Кстати, вот общий метод извлечения N-го аргумента любого вариационного шаблона:
#include <tuple>
template<typename... Args>
class Foo {
public:
template <int N>
using Nth = typename std::remove_reference<decltype(std::get<N>(std::declval<std::tuple<Args...>>()))>::type;
};
int main() {
Foo<int, float>::Nth<1> val = 3.14159f;
return 0;
}