普遍参考 (即“前向引用”) c++
标准名称)和完美的转发 c++11
, c++14
以及其他方面有许多重要的优点;看到 这里,和 这里。
在上面引用的Scott Meyers的文章中(链接),根据经验表明:
如果声明变量或参数具有类型 Ť&& 对于一些 演绎类型 T,该变量或参数是通用参考。
例1
实际上,使用clang ++我们看到以下代码片段将成功编译 -std=c++14
:
#include <utility>
template <typename T>
decltype(auto) f(T && t)
{
return std::forward<T>(t);
}
int x1 = 1;
int const x2 = 1;
int& x3 = x1;
int const& x4 = x2;
// all calls to `f` result in a successful
// binding of T&& to the required types
auto r1 = f (x1); // various lvalues okay, as expected
auto r2 = f (x2); // ...
auto r3 = f (x3);
auto r4 = f (x4);
auto r5 = f (int()); // rvalues okay, as expected
给出通用引用(前向引用)和类型推导的任何描述(例如,参见 这个解释)很清楚为什么上述工作。虽然,从同样的解释来看,为什么以下也不能起作用并不是很清楚。
(失败)例2
这个问题 解决了同样的问题。但是,提供的答案并不能解释为什么模板化类型不被归类为“推断”。
我要展示的(看似)满足Meyers的上述要求。但是,以下代码剪断了 失败 编译,产生错误(以及每次调用的错误 f
):
test.cpp:23:11:错误:调用'f'没有匹配函数
auto r1 = f(x1);
test.cpp:5:16:注意:候选函数[有T = foo,A = int]没有 可行:没有已知的从'struct foo <int>'到'foo <int> &&'的转换 第一个论点
decltype(auto)f(T <A> && t)
#include <utility>
//
// It **seems** that the templated type T<A> should
// behave the same as an bare type T with respect to
// universal references, but this is not the case.
//
template <template <typename> typename T, typename A>
decltype(auto) f (T<A> && t)
{
return std::forward<T<A>> (t);
}
template <typename A>
struct foo
{
A bar;
};
struct foo<int> x1 { .bar = 1 };
struct foo<int> const x2 { .bar = 1 };
struct foo<int> & x3 = x1;
struct foo<int> const& x4 = x2;
// all calls to `f` **fail** to compile due
// to **unsuccessful** binding of T&& to the required types
auto r1 = f (x1);
auto r2 = f (x2);
auto r3 = f (x3);
auto r4 = f (x4);
auto r5 = f (foo<int> {1}); // only rvalue works
在上下文中,因为类型 T<A>
的 f
的参数 是 推断,肯定是参数声明 T<A>&& t
将表现为通用参考(前向参考)。
示例3(为了清楚地描述手头的问题)
让我强调以下内容:代码失败 Example 2
编译是 不 由于这个事实 struct foo<>
是模板类型。失败似乎是原因 只要 通过声明 f
作为模板类型的参数。
考虑以前对以前代码的修订 不 编译:
#include <utility>
//
// If we re-declare `f` as before, where `T` is no longer a
// templated type parameter, our code works once more.
//
template <typename T>
decltype(auto) f (T && t)
{
return std::forward<T> (t);
}
//
// Notice, `struct foo<>` is **still** a templated type.
//
template <typename A>
struct foo
{
A bar;
};
struct foo<int> x1 { .bar = 1 };
struct foo<int> const x2 { .bar = 1 };
struct foo<int> & x3 = x1;
struct foo<int> const& x4 = x2;
// all calls to `f` (again) result in
// a successful binding of T&& to the required types
auto r1 = f (x1);
auto r2 = f (x2);
auto r3 = f (x3);
auto r4 = f (x4);
令我惊讶的是,这个简单的改变完全改变了模板函数类型推导的行为 f
的类型参数。
问题:
为什么第二个例子不能按预期工作?是否存在使用模板化类型克服此问题的技术 c++11/14
?是否有众所周知的现存代码库(在野外)成功使用 c++
带有模板类型的前向引用?