考虑这段代码,它使用具有函数模板的常用习惯用法构造专门用于推导类型的类模板的实例,如std::make_unique和std::make_tuple以下所示:
template <typename T>
struct foo
{
std::decay_t<T> v_;
foo(T&& v) : v_(std::forward<T>(v)) {}
};
template <typename U>
foo<U> make_foo(U&& v)
{
return { std::forward<U>(v) };
}
Run Code Online (Sandbox Code Playgroud)
在斯科特迈尔斯'通用引用’的上下文中,所述参数
make_foo是一个普遍的基准,因为它的类型是U&&其中U推导出.到的构造函数的参数foo不是通用参考,因为尽管其类型为T&&,T是(通常)不能推导出.
但是在foo调用构造函数的情况下,在make_foo我看来,将构造函数的参数foo看作是一个通用引用可能是有意义的,因为T它是由函数模板推导出来的make_foo.将应用相同的参考折叠规则,以便v两个函数中的类型相同.在这种情况下,无论是T
和U可以说已经推出.
所以我的问题是双重的:
foo在有限的情况下,将构造函数的参数视为通用引用是否有意义T,在调用者的通用引用上下文中,如在我的示例中那样?std::forward明智的用途吗?c++ language-lawyer perfect-forwarding c++11 universal-reference
以下定义了一个min函数
template <typename T, typename U>
constexpr auto
min(T&& t, U&& u) -> decltype(t < u ? t : u)
{
return t < u ? t : u;
}
Run Code Online (Sandbox Code Playgroud)
有一个问题:它似乎写得完全合法
min(10, 20) = 0;
Run Code Online (Sandbox Code Playgroud)
这已经过Clang 3.5和g ++ 4.9的测试.
解决方案很简单,只是std::forward用来恢复参数的"rvalue-ness",即修改正文和decltype说
t < u ? std::forward<T>(t) : std::forward<U>(u)
Run Code Online (Sandbox Code Playgroud)
但是,我无法解释为什么第一个定义不会产生错误.
鉴于我的转发和普遍引用,两者的理解t和u演绎他们的论据类型,int&&当传递整数常量.但是,在正文中min,参数有名称,因此它们是左值.现在,条件运算符的真正复杂规则发挥作用,但我认为相关的是:
- E2 [和] E3都是相同类型的glvalues.在这种情况下,结果具有相同的类型和值类别.
因此,返回类型operator?:应该是int&&为好,应该不是吗?但是,(据我所知),Clang和g ++都 …
c++ conditional-operator rvalue-reference c++11 universal-reference
我最近看了一下这个视频,解释了C++中概念精简版的概念,这些概念很可能在今年作为TS出现.现在,我也了解通用引用/转发引用(如描述在这里),并是t &&可以根据上下文两个方面的含义(即,如果类型推演正在执行或没有).这自然会引出概念如何与通用引用相互作用的问题?
为了使它具体化,在下面的例子中我们有
void f(int&& i) {}
int i = 0;
f(i); // error, looks for f(int&)
f(0); // fine, calls f(int&&)
Run Code Online (Sandbox Code Playgroud)
和
template <typename T>
void f(T&& test) {}
int i = 0;
f(i); // fine, calls f(T&&) with T = int& (int& && = int&)
f(0); // fine, calls f(T&&) with T = int&& (int&& && = int&&)
Run Code Online (Sandbox Code Playgroud)
但是如果我们使用概念会发生什么?
template <typename T>
requires Number<T>
void f(T&& test) {}
template <Number T>
void g(T&& test) …Run Code Online (Sandbox Code Playgroud) c++ c++-concepts universal-reference forwarding-reference c++17
如何专门化一个采用通用参考参数的函数模板?
foo.hpp:
template<typename T>
void foo(T && t) // universal reference parameter
Run Code Online (Sandbox Code Playgroud)
Foo.cpp中
template<>
void foo<Class>(Class && class) {
// do something complicated
}
Run Code Online (Sandbox Code Playgroud)
在这里,Class不再是推断类型,因此是Class完全; 它不可能是Class &,所以参考折叠规则对我没有帮助.我或许可以创建另一个带Class &参数的特化(我不确定),但这意味着foo为所有参数的rvalue/lvalue引用的每个可能组合复制所包含的所有代码,这是通用引用应该避免的.
有没有办法实现这个目标?
如果有更好的解决方法,请更具体地说明我的问题:
我有一个可以连接到多个游戏服务器的程序,并且每个服务器在大多数情况下都使用相同的名称调用所有内容.但是,对于一些事情,它们的版本略有不同.这些东西可以有几个不同的类别:移动,项目等.我写了一个通用的"移动字符串移动枚举"内部代码调用的函数集,我的服务器接口代码有类似的功能.但是,有些服务器有自己的内部ID,它们与之通信,有些使用字符串,有些则在不同情况下使用.
现在我想做的是让它更通用一点.
我希望能够打电话ServerNamespace::server_cast<Destination>(source).这将允许我从a转换Move为a std::string或ServerMoveID.在内部,我可能需要制作副本(或从中移动),因为某些服务器要求我保留已发送消息的历史记录.通用引用似乎是解决这个问题的明显方法.
我现在想到的头文件只会暴露出来:
namespace ServerNamespace {
template<typename Destination, typename Source>
Destination server_cast(Source && source);
}
Run Code Online (Sandbox Code Playgroud)
并且实现文件将所有合法转换定义为模板特化.
c++ templates template-specialization c++11 universal-reference
据我所知,在C++ 11中,应始终使用通用引用std::forward,但我不确定如果std::forward不使用会出现什么样的问题.
template <T>
void f(T&& x);
{
// What if x is used without std::forward<T>(x) ?
}
Run Code Online (Sandbox Code Playgroud)
你能否举例说明在这种情况下可能出现的问题?
为什么在带有通用引用参数的构造函数的类中不会出现右值优化?
http://coliru.stacked-crooked.com/a/672f10c129fe29a0
#include <iostream>
template<class ...ArgsIn>
struct C {
template<class ...Args>
C(Args&& ... args) {std::cout << "Ctr\n";} // rvo occurs without &&
~C(){std::cout << "Dstr\n";}
};
template<class ...Args>
auto f(Args ... args) {
int i = 1;
return C<>(i, i, i);
}
int main() {
auto obj = f();
}
Run Code Online (Sandbox Code Playgroud)
输出:
Ctr
Ctr
Dstr
Ctr
Dstr
Dstr
Run Code Online (Sandbox Code Playgroud) 我有一个函数,可以通过通用引用接受任何类型,并希望为特定类型重载它(其中一些是自己模板化的,虽然我不认为这在这里很重要).不幸的是,我似乎无法以正确的顺序解决重载问题.
我会假设第二个声明会更受欢迎,foo因为它更具体(模板化程度更低),尽管看起来我对重载决策的理解有些缺乏.有趣的是,将第二个声明更改为X值,使得它打印"好,好"并且X通过非const引用使其打印"坏,好".显然,删除第一个声明会使它返回"好,好",因为没有其他选择.
那么为什么会这样呢?最重要的是,如果以下代码不起作用,如何使用此签名重载函数?
#include <iostream>
#include <string>
class X {};
template<typename T>
inline std::string foo(T && rhs) {
return "bad";
}
inline std::string foo(const X & rhs) {
return "good";
}
int main() {
std::cout << foo(X()) << std::endl;
X x;
std::cout << foo(x) << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编辑:
也许更迂回的解决方案是间接地做到这一点.摆脱第一种形式foo并使用SFINAE检查是否存在有效的过载,然后它不会调用foo_fallback.
我需要在类中存储通用引用(我确信引用的值将比类更长).这样做有规范的方法吗?
这是我想出的最小例子.它似乎有效,但我不确定我是否做对了.
template <typename F, typename X>
struct binder
{
template <typename G, typename Y>
binder(G&& g, Y&& y) : f(std::forward<G>(g)), x(std::forward<Y>(y)) {}
void operator()() { f(std::forward<X>(x)); }
F&& f;
X&& x;
};
template <typename F, typename X>
binder<F&&, X&&> bind(F&& f, X&& x)
{
return binder<F&&, X&&>(std::forward<F>(f), std::forward<X>(x));
}
void test()
{
int i = 1;
const int j = 2;
auto f = [](int){};
bind(f, i)(); // X&& is int&
bind(f, j)(); // X&& is const int&
bind(f, …Run Code Online (Sandbox Code Playgroud) 在c ++ 11之前,我曾经写过这样的代码:
// Small functions
void doThingsWithA(const A& a)
{
// do stuff
}
void doThingsWithB(const B& b)
{
// do stuff
}
void doThingsWithC(const C& c)
{
// do stuff
}
// Big function
void doThingsWithABC(const A& a, const B& b, const C& c)
{
// do stuff
doThingsWithA(a);
doThingsWithB(b);
doThingsWithC(c);
// do stuff
}
Run Code Online (Sandbox Code Playgroud)
但是现在,使用移动语义,允许我的函数将rvalue引用作为参数并添加这些重载可能会变得有趣(至少在某些情况下):
void doThingsWithA(A&& a);
void doThingsWithB(B&& b);
void doThingsWithC(C&& c);
Run Code Online (Sandbox Code Playgroud)
从我收集的内容来看,如果我想在我的大函数中调用那些重载,我需要使用完美的转发,这可能看起来像这样(它的可读性稍差,但我想它可以用模板类型的良好命名约定):
template<typename TplA, typename TplB, typename TplC>
void doThingsWithABC(TplA&& a, TplB&& b, TplC&& …Run Code Online (Sandbox Code Playgroud) c++ perfect-forwarding c++11 universal-reference forwarding-reference
考虑这两个重载:
template <typename T> void foo(T &) {}
template <typename T> void foo(T &&) {}
Run Code Online (Sandbox Code Playgroud)
它们可能含糊不清吗?
下面的代码用Clang 3.4编译,但是GCC 4.8失败了,它说过载(第一个带有T = int,第二个有T = int&)是不明确的.
int main()
{
int n = 10;
foo(n);
}
Run Code Online (Sandbox Code Playgroud)
我意识到"绑定到引用"在重载分辨率方面是一个"完全匹配",所以我想这个问题归结为一个推论T = int/ T = int&优于另一个,或者它们是否同样好.
c++ rvalue-reference overload-resolution c++11 universal-reference