我看过很多介绍可变参数模板的链接。但我从未见过任何可编译的示例来演示这种方法。

有人可以给我提供一些可以找到此类可编译示例的链接吗?

有帮助吗?

解决方案

Variadic模板是尚未正式发布的C ++ 0x标准的一部分。它们自第4.3版以来得到GCC的支持,但是您需要通过添加编译器开关-STD = C ++ 0x来启用C ++ 0x的支持。

其他提示

最简单的示例之一是以下实现 max 甚至没有在类型上模板。

int maximum(int n)
{
    return n;
}

template<typename... Args>
int maximum(int n, Args... args)
{
    return max(n, maximum(args...));
}

只有稍微复杂的是规范 printf 执行:

void printf(const char *s)
{
  while (*s)
  {
    if (*s == '%' && *(++s) != '%')
      throw "invalid format string: missing arguments";
    std::cout << *s++;
  }
}

template<typename T, typename... Args>
void printf(const char* s, T value, Args... args)
{
  while (*s)
  {
    if (*s == '%' && *(++s) != '%')
    {
      std::cout << value;
      printf(s, args...); // call even when *s == 0 to detect extra arguments
      return;
    }
    std::cout << *s++;
  }
  throw "extra arguments provided to printf";
}

Variadic模板是C ++ 0x功能,主要针对通用库的作者。我不希望在“用户代码”中看到它们。例如,在C ++ 0x标准库中,它们在许多地方使用:std :: function,std :: async,std :: reference_wrapper,std :: tuple,std,std :: packaged_task,...

为了给您一个示例,我将向您展示如何相对于variadic模板实现参考_wrapper:

template<class T>
class reference_wrapper
{
    T *ptr;
public:
    explicit reference_wrapper(T& thing) : ptr(&thing) {}
    explicit reference_wrapper(T&&     ) = delete;

    operator T&() const {return *ptr;}

    template<class... Args>
    decltype( declval<T&>()(declval<Args>()...) )
    operator()(Args&&... args) const
    {
        return (*ptr)(forward<Args>(args)...);
    }
};

这并不完全符合标准草稿,但应该在几乎没有修改的情况下进行编译。它演示了多个C ++ 0x功能:

  • 删除功能(禁用RVALUE的构造函数)
  • RVALUE参考(将RVALUE参数检测到构造函数,完美的转发)
  • 通过 decltype
  • 标准库功能模板 declval 创建对象以构建表达式的目的 decltype (GCC尚未提供此功能模板。您必须自己写)
  • variadic模板(接受任意数量的参数)

variadic成员模板的目的是将参数转发给所引用的对象 ptr. 。如果T是功能指针类型或具有重载函数调用操作员的类型,则应该有效。

干杯! s

可变参数模板的一个非常简单的示例:

假设我们想要一个函数,它接受可变数量的参数并将它们全部打印出来。例如:

print("Hello", 1, 3.14, 5L);

为了使该功能正常工作,我们基本上需要两个函数:

第一个是一个带有可变数量参数的函数:

template<typename T, typename... Args>
void print(T t, Args ...args){
     std::cout << t << ", ";
     print(args...);
}

一些解释:

1.) 参数包以省略号(...) 表示,出现在参数列表中。

typename...Args 
        |  | << Optional whitespace. Can have multiple whitespaces in between them
    Args...args

这意味着,这些都是相同的。

typename ...args
typename...args
typename   ...   args

因此,您不必担心其中空白的正确位置。不过,IMO 最多应使用一个空格作为最佳实践。

2.) 包扩展:模式后跟省略号。

print(args...); //expand when you wish to use them

3.) 参数包接受 零个或多个 模板参数。所以, print(T t, Args... args) 接受 一个或多个 参数。


一旦您理解了这一点,我们就可以将调用流程可视化如下:

print("Hello", 1, 3.14, 5L);

翻译为:

print(string, int, float, long);

哪个调用

print(int, float, long);

哪个调用

print(float, long);  // say Level 2

哪个调用

print(long);         // say Level 1

哪个调用

print();             // say Level 0

如果您仔细遵循了第 3 点,您一定已经意识到 print(T t, Args... args) 无法处理 0 级呼叫。
因此,我们需要另一个具有相同名称的函数来赶上任何级别 >=0 的情况。


第二个,一个函数 抓住 调用堆栈顶部的调用:

在 0 级捕获:

void print(){}

或者,在级别 1 捕获:

template<typename T>
void print(T t){ std::cout << t;}

或者,在第 2 级捕获:

template<typename T, typename U>
void print(T t, U u){ std::cout << t << ", " << u;}

很快...

其中任何一个都可以。希望这对您下次编写此类函数或类时有所帮助。

这是我在博客上放置的variadic模板的一个示例:http://thenewcpp.wordpress.com/2011/11/23/variadic-templates-part-part-1-2/

它编译。它演示了从一组类型的类型中找到最大类型。

#include <type_traits>

template <typename... Args>
struct find_biggest;

//the biggest of one thing is that one thing
template <typename First>
struct find_biggest<First>
{
  typedef First type;
};

//the biggest of everything in Args and First
template <typename First, typename... Args>
struct find_biggest<First, Args...>
{
  typedef typename find_biggest<Args...>::type next;
  typedef typename std::conditional
  <
    sizeof(First) >= sizeof(next),
    First,
    next
  >::type type;
};

在C ++ 11之前,您只能使用固定的参数计数创建模板。

使用一个参数为函数的FIRTS模板。

使用两个参数的函数的第二个模板。 ... IE

由于C ++ 11您只能编写一个模板,因此编译器将生成所需的功能本身。

好例子http://eli.thegreenplace.net/2014/variadic-templates-in-c/

另一种语法:扩展,例如

template<typename VAL, typename... KEYS>
class MyMaps
{
  typedef std::tuple< std::map<KEYS,VAL>... > Maps;
}

因此:

MyMaps<int,int,string>:Maps

现在实际上是:

std::tuple<std::map<int,int>,std::map<string,int> >
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top