可变个数参数

先给个简单的例子

#include <iostream>
#include <utility>

struct foo {
  foo() {
    std::cout << "default ctor!\n";
  }

  foo(const foo&) {
    std::cout << "copy ctor!\n";
  }

  foo(foo&&) {
    std::cout << "move ctor!\n";
  }

};

std::ostream&
operator<<(std::ostream& out, const foo& f) {
  out << "foo";
  return out;
}

template <typename Arg> void
print_impl(Arg&& arg) {
  std::cout << arg << '\n';
}

template <typename Arg, typename... Args> void
print_impl(Arg&& arg, Args&&... args) {
  std::cout << arg << ", ";
  print_impl(std::forward<Args>(args)...);
}

template <typename... Args> inline void
print(Args&&... args) {
  print_impl(std::forward<Args>(args)...);
}

int
main(int, char**) {
  std::string a = "hello";
  foo b;
  print(1, a, std::string("world"), foo(), b, 2);

  return 0;
}

这时因为完全使用了引用没有调用构造函数。如果在 print 里面使用 Arg arg1(std::forward(arg)) 的话,一个会调用 move constructor,另一个会传递引用,Arg 成为 Foo& 所以没有调用构造函数。

这个功能与 lambda 一起用的时候有个诡异的问题,比如我们通过 lambda capture 传递的若干 functor。

#include <iostream>
#include <functional>
#include <utility>

template <typename Arg> inline void
evaluate(Arg& arg) {
 arg();
}

template <typename Arg, typename... Args> inline void
evaluate(Arg& arg, Args&... args) {
 arg();
 evaluate(args...);
}

template <typename... Args>
inline std::function<void ()>
combine(Args&&... args) {
 return [args...] () mutable {
 evaluate(args...);
 };
}

struct foo {
 foo() {
 std::cout << "foo ctor\n";
 }

 void operator()() {
 std::cout << "foo is doing something\n";
 }
};

struct bar {
 bar() {
 std::cout << "bar ctor\n";
 }

 void operator()() {
 std::cout << "bar is doing something\n";
 }
};

int
main(int, char**) {
 bar b;
 auto f = combine(foo(), b);
 f();

 return 0;
}

看起来没啥语法错误,但是 gcc4.9 之前 都没法正确的编译。看到一个无奈的解决方案,在 gcc4.9 普及之前不要太过分的使用 C++11 的语言特性 ~><~

——————
And the sons of Jacob came out of the field when they heard it:and the men were grieved, and they were very wroth, because he had wrought folly in Israel in lying with Jacob’s daughter; which thing ought not to be done

Advertisements
可变个数参数

一个有关“可变个数参数”的想法

    1. zt 说:

      原来如此,一直不理解为啥 C++ 不提供一个 compile-time 的 API 供我们更好的遍历变长参数,这样编译器不是能更好的优化生成的代码吗?还是说现在这样写的递归代码编译器已经可以优化成为非递归的形式了?

      1. Before C++14 committee draft is out in Chicago, there is a paper trying to address this in library http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3761.html
        But 1. it ws too late for C++14; 2. as a library solution, there are some details need to discussed, like not permitting user to specialize this even with user-defined types, otherwise we cannot optimize it, and it may want to specify error behavior (like SFINAE-friendly); 3. needs to talk to EWG to see whether they can come up with a language feature.

        The paper was sent back and we hope it can come back after C++14. There is no update on this paper yet, but some very powerful parameter pack enhancement was presented in Rapperswil meeting: (paper: http://atpp.irrequietus.eu/atpp-bdb29d2.pdf slides: https://docs.google.com/viewer?a=v&pid=forums&srcid=MTEwODAzNzI2MjM1OTc0MjE3MjkBMDMyODA2ODc2Njg5OTUwNzIyMTMBc0UwbGYtYVlHR29KATAuMQFpc29jcHAub3JnAXYy) With this, the users may not need to access parameter packs with index at all.

        Compiles (clang, at least) execute compile-time recursions very well. Only your algorithm matters.

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s