我有以下代码:
#include <iostream>
#include <typeinfo>
template <typename T>
struct A : T {
template <typename ...Args>
A(Args&&... params) : T(std::forward<Args>(params)...), x(0) {
std::cout << "Member 'x' was default constructed\n";
}
template <typename O, typename ...Args, typename = typename std::enable_if<std::is_constructible<int,O>::value>::type>
A(O o, Args&&... params) : T(std::forward<Args>(params)...), x(o) {
std::cout << "Member 'x' was constructed from arguments\n";
}
int x;
};
struct B{
B(const char*) {}
};
int main() {
A<B> a("test");
A<B> y(3, "test");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它工作正常,并打印
Member 'x' was …Run Code Online (Sandbox Code Playgroud) c++ overloading variadic-templates c++11 universal-reference
例:
template <typename T>
class Bar
{
public:
void foo(T&& arg)
{
std::forward<T>(arg);
}
};
Bar<int> bar;
bar.foo(10); // works
int a{ 10 };
bar.foo(a); // error C2664: cannot convert argument 1 from 'int' to 'int &&'
Run Code Online (Sandbox Code Playgroud)
通用引用似乎只适用于模板化函数,只适用于类型推导,对吧?所以在课堂上使用它没有意义吗?std::forward在我的案例中使用是否有意义?
我有一个函数,它排序两个向量,其中第一个作为排序标准.它的签名是
template<typename A, typename B>
void sort(A&& X, B&& Y)
{
..
}
Run Code Online (Sandbox Code Playgroud)
问题是普遍引用会允许无意义的案例
sort(vector<int>{ 2,1,3 }, vector<int>{ 3,1,2 });
Run Code Online (Sandbox Code Playgroud)
其后rvalue将被销毁(废话).
明确询问左值是不起作用的
template<typename A, typename B>
void sort(A& X, B& Y) ... // (*)
sort(vector<int>{2,1,3}, vector<int>{3,1,2});
Run Code Online (Sandbox Code Playgroud)
由于某种原因上面的编译(我认为只允许const值左右绑定到rvalues并延长它们的生命周期?).
如果我添加const到左值引用,那么该函数将不再能够修改向量并对它们进行排序.
我的问题是:
1)为什么在标有的示例中,// (*)我可以将rvalue绑定到不均匀的左值const?为什么int& r = 20;不允许这样的东西呢?有什么不同?
2)我如何解决我的问题,即函数只接受左值而不是右值临时值?(如果可能,当然)
显然我可以使用任何可用的C++版本
在函数中我需要区分左值和右值引用,所以明显的路径是重载:
void myfunc(A&& a);
void myfunc(const A& a);
Run Code Online (Sandbox Code Playgroud)
这具有完全所需的行为,具有良好定义的类型和隐式转换.然而,代码重复太多,我宁愿将相关决策封装在内部,只保留一个函数,因此通过通用引用可能是一个选项:
template <typename A> void myfunc(A&& a);
Run Code Online (Sandbox Code Playgroud)
然而,这有一个令人遗憾的缺点,即现在任何对象都可以作为第一个参数传递,因此可以通过enable_if强加约束:
template <typename T, class = typename enable_if<
is_same<typename remove_const<typename remove_reference<T>::type>::type, A>::value,
T>::type>
void myfunc( T&& a);
Run Code Online (Sandbox Code Playgroud)
这几乎似乎可以完成这项工作,但是(我想已经通过模板化)我们已经失去了一个很好的重载属性,可以触发隐式转换构造函数到类型A(比如来自类型C参数).重载不是一个选项,因为某些函数可能有3个或更多A &&参数,无意处理组合爆炸.隐式转换可以以某种方式恢复吗?当然,一种解决方法可能是例如为A添加其他允许的参数类型,并在main函数中执行任何所需的转换,但这是侵入性的,丑陋的,明确的含义并产生混淆(原始C参数可能是左值[reference]并通过转换产生右值).有更好的方法吗?
在下面,是&&一个普遍的参考?
template <class Function = std::greater<int> > void f(Function&& f = Function());
Run Code Online (Sandbox Code Playgroud) 我一直在尝试使用模板成员函数在我的类中设置一个值.我想用一个通用的参考,这样我可以接受的正确类型的任何变体(例如T,T&,T&&,const T,const T&,const T&&)
但是,似乎我的成员函数只接受rvalues,而不像接受通用引用的自由函数.
template <typename T>
class Foo{
public:
void memberURef(T&& t){
val = std::forward<T>(t);
}
private:
T val;
};
template <typename T>
void freeURef(T&& t){
}
int main() {
int lval = 1;
const int clval = 1;
freeURef(lval); // fine
freeURef(clval); // fine
Foo<int> foo;
foo.memberURef(2);
foo.memberURef(lval); //error: cannot bind 'int' lvalue to 'int&&'
foo.memberURef(clval); //error: no matching function for call to 'Foo<int>::memberURef(const int&)' …Run Code Online (Sandbox Code Playgroud) 可能我的理解explicit是不够的,但我想知道为什么在下面的代码中,当我将后者声明为后,复制构造函数不会被异步引用构造函数隐藏explicit.
struct A
{
A() = default;
template<typename T>
A(T&& t) { std::cout<<"hides copy constructor"<<std::endl; }
};
struct A_explicit
{
A_explicit() = default;
template<typename T>
explicit A_explicit(T&& t) { std::cout<<"does not hide copy constructor?"<<std::endl; }
};
int main()
{
A a;
auto b = a; (void) b; //prints "hides copy constructor"
A_explicit a_exp;
auto b_exp = a_exp; (void) b_exp; //prints nothing
}
Run Code Online (Sandbox Code Playgroud)
这是一个通用的解决方案,而不是SFINAE的东西,否则将适用于防止隐藏A(例如std::enable_if_t<!std::is_same<std::decay_t<T>, A>::value>,看到这里)?
在我的项目中,我的功能如下:
bool VectorList::put(const Pair &p);
Run Code Online (Sandbox Code Playgroud)
这通过复制添加Pair到.VectorListPair
我可以像这样使用它:
Pair p { "key", "value" };
VectorList v;
v.put(p);
// or
v.put(Pair{ "anotherkey", "anothervalue" });
Run Code Online (Sandbox Code Playgroud)
但是在第二种情况下会创建一个不必要的对象,所以我想这样做
bool VectorList::put(Pair &&p);
Run Code Online (Sandbox Code Playgroud)
我检查了如何在vector(gcc,llvm)中完成此操作,并且在两个方法中都有100%相同的代码,除了等于/ std :: move()行.
有没有办法在没有代码重复的情况下做到这一点?
put() 看起来与此类似:
struct Node{
Pair pair;
AdditionalThings at;
};
bool VectorList::put(const Pair &p){
if (not_good_for_insert(p))
return false;
// ...
Node node = create_node();
node.pair = p;
// ...
return true;
}
Run Code Online (Sandbox Code Playgroud) 当派生类复制和移动函数调用它们的基类版本时,我对我所看到的行为感到困惑.
我有一个基类与各种构造函数,告诉我什么时候被调用:
#include <iostream>
class Base {
public:
Base() {}
template<typename T>
Base(T&&) { std::cout << "URef ctor\n"; }
Base(const Base&) { std::cout << "Copy ctor\n"; }
Base(Base& rhs): Base(const_cast<const Base&>(rhs))
{ std::cout << " (from non-const copy ctor)\n"; }
Base(Base&&) { std::cout << "Move ctor\n"; }
Base(const Base&& rhs): Base(rhs)
{ std::cout << " (from const move ctor)\n"; }
};
Run Code Online (Sandbox Code Playgroud)
对于具有编译器生成的复制和移动操作的派生类
class Derived: public Base {};
Run Code Online (Sandbox Code Playgroud)
和这个测试代码,
int main()
{
Derived d;
Derived copyNCLValue(d);
Derived copyNCRvalue(std::move(d));
const Derived cd; …Run Code Online (Sandbox Code Playgroud)