【问题标题】:Easiest way to get the N-th argument of a variadic templated class?获取可变参数模板类的第 N 个参数的最简单方法?
【发布时间】:2012-08-02 10:17:20
【问题描述】:

我想知道在编译时获取可变参数模板类的第 N 个参数的最简单和更常见的方法是什么(返回值必须是编译器的静态 const为了做一些优化)。这是我的模板类的形式:

template<unsigned int... T> MyClass
{
    // Compile-time function to get the N-th value of the variadic template ?
};

非常感谢。

编辑:由于 MyClass 将包含 200 多个函数,我无法对其进行专门化。但我可以专门化 MyClass 中的结构或函数。

编辑:从经过验证的答案得出的最终解决方案:

#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;
}

【问题讨论】:

  • “归纳设计”在这里应该可以很好地工作,您需要一个针对基本案例进行部分专业化的模板。
  • 我在评论中提到的模板不一定是你问题中的模板类,而是一个帮手。

标签: c++ templates metaprogramming variadic-templates


【解决方案1】:

“归纳设计”应该是这样的:

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;
};

【讨论】:

  • 我试过了,我认为这是一个很好的方法,但我在 GCC 4.6.2 上收到以下错误:抱歉,未实现:无法将 'Tail ...' 扩展为固定 -长度参数列表
  • @Vincent:这意味着你的编译器不够新。
【解决方案2】:

这是另一种方法:

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

如果你被“无法将 'T...' 扩展为固定长度的参数列表”http://ideone.com/YF4UJ

【讨论】:

  • 与其他答案相同的问题:抱歉,未实现:无法将“remPack ...”扩展为固定长度的参数列表。有什么技巧可以避免这种情况?
  • @Vincent 你试过最后一个测试网址liveworkspace.org/code/e44f694c0ed618c3ad493dcc9bf3d347吗?
  • 完美!像魅力一样工作,而且都在编译时!非常感谢
  • 很困惑为什么你决定添加一个相同的答案,而我的也适用于最新的 g++:liveworkspace.org/code/1ed1244b61a6689935eea8e33e4fb873
  • 如果我没看错的话,将第一个索引设为 1 而不是 0 有点奇怪。
【解决方案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;
};

【讨论】:

  • 这不能与 ICC(版本 15.0.2)一起编译。它引发错误:“constexpr”在此处无效。如果我将值设为static,则会出现另一个错误:“const T []”类型的成员不能有类内初始化程序
【解决方案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; 
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-03
    • 1970-01-01
    • 1970-01-01
    • 2021-02-11
    • 1970-01-01
    • 2019-11-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多