在这样的代码中:
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 限定符无关。
我对那段代码有3个疑惑。
(1) 是
declval
返回类型仍然是通用引用吗?例如,declval<T>()
, 与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
内部被实例化.
最佳答案
这两种情况不是等价的。这个例子:
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)...); }
关于c++ - 类模板实例化和通用引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43334951/