标签: universal-reference

当参数是引用时,可变参数模板构造函数选择失败

我有以下代码:

#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

4
推荐指数
1
解决办法
669
查看次数

带模板类的通用引用

例:

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在我的案例中使用是否有意义?

c++ templates universal-reference

4
推荐指数
2
解决办法
1098
查看次数

函数只接受非常量左值

我有一个函数,它排序两个向量,其中第一个作为排序标准.它的签名是

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++版本

c++ vector c++11 universal-reference c++14

4
推荐指数
1
解决办法
518
查看次数

如何将类型约束和隐式转换与C++ 11通用引用相结合?

在函数中我需要区分左值和右值引用,所以明显的路径是重载:

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]并通过转换产生右值).有更好的方法吗?

c++ c++11 universal-reference forwarding-reference

4
推荐指数
1
解决办法
211
查看次数

默认模板类型可以是通用引用吗?

在下面,是&&一个普遍的参考?

template <class Function = std::greater<int> > void f(Function&& f = Function());
Run Code Online (Sandbox Code Playgroud)

c++ templates reference c++11 universal-reference

3
推荐指数
1
解决办法
156
查看次数

具有通用引用的成员函数模板将不接受左值

我一直在尝试使用模板成员函数在我的类中设置一个值.我想用一个通用的参考,这样我可以接受的正确类型的任何变体(例如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)

c++ templates c++11 universal-reference

3
推荐指数
1
解决办法
476
查看次数

C++显式通用引用构造函数不隐藏复制构造函数?

可能我的理解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)

DEMO

这是一个通用的解决方案,而不是SFINAE的东西,否则将适用于防止隐藏A(例如std::enable_if_t<!std::is_same<std::decay_t<T>, A>::value>,看到这里)?

c++ copy-constructor c++11 universal-reference

2
推荐指数
2
解决办法
188
查看次数

通用引用c ++ 11代码重复

在我的项目中,我的功能如下:

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)

c++ dry c++11 universal-reference

2
推荐指数
1
解决办法
116
查看次数

为什么派生类中复制/移动函数的"正常"实现的行为会有所不同,具体取决于它们的定义方式?

当派生类复制和移动函数调用它们的基类版本时,我对我所看到的行为感到困惑.

我有一个基类与各种构造函数,告诉我什么时候被调用:

#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)

c++ constructor-overloading c++11 universal-reference

1
推荐指数
1
解决办法
124
查看次数