3

在这样的代码中:

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存在并将一组参数发送到一个函数或另一个函数,并且可以使用传递的参数调用,保持完整(我猜)它们的确切传递类型,以及当它的返回类型为 时int,不管引用或 const限定词。

我对那段代码有三个疑问。

  • (1)declval返回类型仍然是通用引用吗?例如,declval<T>(), with T = int&, 它的返回类型是int&&(一个真正的 r 值引用),还是在传递给另一个调用时int & &&再次推导出为int&遵循通用引用的通常规则?我认为它没有(正如@101010 所指出的),但我不知道在这种情况下如何进行完美的重载测试。

  • (2)是否需要重新指定可变参数模板才能使用通用引用推导规则,或者由于(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,它只会在内部实例化test

4

1 回答 1

1

这两种情况是等价的。这个例子:

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)...); }
于 2017-04-11T14:01:01.937 回答