Class 模板实例化和通用引用

Class template instantiations and universal references

在这样的代码中:

template<class...> struct pack{};

template<class, class = int>
struct call_t
{
    template<class... args_t>
    static int apply(args_t&&...)
    { return 0; }
};

template<class... args_t>
struct call_t<pack<args_t...>, // (1)
        std::decay_t<decltype(convert(declval<args_t>()...))> >
{
    template<class... params_t> // (2)
    static int apply(params_t&&... args)
    { return convert(std::forward<params_t>(args)...); }
};

template<class... args_t>
auto test(args_t&&... args) // (3)
{
    return call_t<pack<args_t...> >::
       apply(std::forward<args_t>(args)...);
}

这个函数根据一个函数 convert 是否存在并且可以用传递的参数调用,保持完整(我猜)它们的确切传递类型,以及何时它的 return 类型是 int,与引用或 const 限定符无关。

我对那段代码有3个疑惑

或者我可以只写

template<class... args_t>
struct call_t<pack<args_t...>, // (1)
        std::decay_t<decltype(convert(declval<args_t>()...))> >
{
    // (2)
    static int apply(args_t... args)
    { return convert(args...); }
};

?

call_t 模板 class 是一个实现细节,因此,它只会在 test 内部实例化。

这两种情况等同。这个例子:

template<class... args_t>
struct call_t<pack<args_t...>, // (1)
        std::decay_t<decltype(convert(declval<args_t>()...))> >
{
    // (2)
    static int apply(args_t... args)
    { return convert(args...); }
};

不转发任何东西。参数包 args... 是左值,因为它们有名称。这与这段代码非常不同:

template<class... params_t> // (2)
static int apply(params_t&&... args)
{ return convert(std::forward<params_t>(args)...); }

其中args...转发。由此产生的行为是新示例可能比旧示例慢(执行复制而不是移动)或者可能会出人意料地无法编译。考虑 convert(std::unique_ptr<int> ) 可通过 args_t = {std::unique_ptr<int>} 调用,但内部 apply() 会失败,因为您将尝试复制 unique_ptr.

你需要做的:

static int apply(args_t... args)
{ return convert(std::forward<args_t>(args)...); }