C++ 向后可变模板

C++ 向后可变模板,c++,c++11,variadic-templates,C++,C++11,Variadic Templates,我想编写一个模板函数来实现这一点(伪代码): 我的尝试包括将可变参数作为第一个参数,如下所示: template<typename A, typename B> inline void shift(A& a, const B& b) noexcept { a = b; } template<typename B, typename C, typename... AA> inline void shift(AA&... aa, B& b,

我想编写一个模板函数来实现这一点(伪代码):

我的尝试包括将可变参数作为第一个参数,如下所示:

template<typename A, typename B>
inline void shift(A& a, const B& b) noexcept {
  a = b;
}
template<typename B, typename C, typename... AA>
inline void shift(AA&... aa, B& b, const C& c) noexcept {
  shift(aa...,b);
  shift(b,c);
}
编辑: 好的,这个特殊的问题当然可以通过颠倒函数参数的顺序来解决:

template<typename A, typename B>
inline void shift(const B& b, A& a) noexcept {
  a = b;
}
template<typename C, typename B, typename... AA>
inline void shift(const C& c, B& b, AA&... aa) noexcept {
  shift(b,aa...);
  b = c;
}
模板
内联无效移位(常量B&B、A&A)无例外{
a=b;
}
模板
内联无效移位(常量C&C、B&B、AA和…AA)无例外{
班次(b、aa等);
b=c;
}

但我仍然想知道语法是否允许将变量参数放置在除最后一个之外的任何位置,以及在什么情况下?

正如T.C.下面的评论所指出的,在您的第一个示例中,
aa
处于非推断上下文中(14.8.2.5 p5定义了非推断上下文,包括“不出现在参数声明列表末尾的函数参数包”),因此无法推断参数包

如果语法允许将变量参数放置在除最后一个之外的任何位置,在什么情况下

除了上述导致第一个示例出现问题的限制外,模板参数包必须是最后一个模板参数,除非可以推断出以下所有模板参数。14.1[temp.param]p11:

不应遵循功能模板的模板参数包 通过另一个模板参数,除非该模板参数可以从函数模板的参数类型列表中推导或具有默认参数(14.8.2)

这是可以的,因为两个模板参数包都可以独立于函数参数推导:

template<typename... T, typename... U>
  void f(std::tuple<T...>, std::tuple<U...>)
  { }

[完全披露:我撰写了Hana]

我不想回答你原来的问题,因为乔纳森做得很好

但是,如果您正在寻找问题的解决方案,并且您可以访问一个无错误的C++14编译器(因此现在使用Clang),您可以使用。Hana是一个现代元编程库,它使您能够在保持高抽象级别的同时进行元编程。因此,您可以以可读的方式编写所需内容,而无需了解该语言的所有肮脏技巧。该库为您解决了这一问题:

#include <boost/hana.hpp>
#include <functional> // for std::ref
#include <iostream>
namespace hana = boost::hana;

template <typename T0, typename ...T>
void shift(T0&& t0, T&& ...ts) {
    auto args = hana::make_tuple(std::ref(t0), std::ref(ts)...);
    hana::for_each(hana::range_c<int, 0, sizeof...(ts)>, [&](auto i) {
        args[i].get() = args[i + hana::int_c<1>].get();
    });
}

int main() {
    int i = 0, j = 1, k = 2;
    shift(i, j, k);
    std::cout << i << ' ' << j << ' ' << k << '\n';
}
#包括
#包含//用于std::ref
#包括
名称空间hana=boost::hana;
模板
无效移位(T0&&T0,T&&ts){
auto args=hana::make_tuple(std::ref(t0),std::ref(ts)…);
hana::for_each(hana::range_c,[&](自动i){
args[i].get()=args[i+hana::int_c].get();
});
}
int main(){
int i=0,j=1,k=2;
移位(i,j,k);

std::cout-Um,模板参数包和函数参数包是不同的东西。
AA
位于模板参数列表的末尾;
AA
不在参数声明列表的末尾,使其成为非推断上下文。@t.C.在Jonathan的示例中,
t
不在其参数列表的末尾,它是一个临时变量后期参数包。但我看不出这与问题中的代码有什么关系@ᐅ约翰内斯乔布利特ᐊ 当然可以。我写评论时的观点是那句话([temp.param]/11)不适用于OP的例子。我不知道这个解决方案的妙趣横生是否给我留下了更深刻的印象,或者它是否真的有意义。逗号运算符的使用很好!对于这样的解决方案,我总是有一个问题,那就是
整数序列
是否得到了优化?@JonathanWakely我不确定e第二个版本-使用
std::tie
将失去顺序保证。
template<typename... T, typename... U>
  void f(std::tuple<T...>, std::tuple<U...>)
  { }
#include <tuple>
#include <iostream>

template<typename... T, size_t... I>
void
shift_impl(std::tuple<T...> t, std::index_sequence<I...>)
{
  // Use pack expansion with comma operator to populate unused array:
  int dummy[] = {
    (std::get<I>(t) = std::get<I+1>(t), 0)...
  };
}

template<typename T0, typename... T>
void
shift(T0&& arg0, T&&... args)
{
  shift_impl(std::tie(arg0, args...), std::index_sequence_for<T...>{});
}

int main()
{
  int i = 0, j = 1, k = 2;
  shift(i, j, k);
  std::cout << i << ' ' << j << ' ' << k << '\n';
}
#include <boost/hana.hpp>
#include <functional> // for std::ref
#include <iostream>
namespace hana = boost::hana;

template <typename T0, typename ...T>
void shift(T0&& t0, T&& ...ts) {
    auto args = hana::make_tuple(std::ref(t0), std::ref(ts)...);
    hana::for_each(hana::range_c<int, 0, sizeof...(ts)>, [&](auto i) {
        args[i].get() = args[i + hana::int_c<1>].get();
    });
}

int main() {
    int i = 0, j = 1, k = 2;
    shift(i, j, k);
    std::cout << i << ' ' << j << ' ' << k << '\n';
}