带有通用引用的 C++ 完美转发可防止类型推导?

问题描述

我考虑了以下 2 个执行相同操作的代码段。在第一种情况下,我不使用通用引用,因此我必须编写函数 set 两次。在第二种情况下,使用通用引用我可以编写一次函数,但类的用户必须明确指定传递给函数 set 的类型。有什么技巧可以同时获得这两个优势吗?

#include <iostream>

struct A {};

template<typename T>
struct B {

    void set(const A& a) {
        a_=a;
    }
    
    void set(A&& a) {
        a_=std::forward<A>(a);
    }

    A a_;
};

int main() {

    B<A> b;
    A a;

    b.set({});
    b.set(a);

    return 0;
}

#include <iostream>

struct A {};

template<typename T>
struct B {

    template<typename U>
    void set(U&& a) {
        a_=std::forward<U>(a);
    }
    
    A a_;
};

int main() {

    B<A> b;
    A a;

    b.set(A{}); // here I can't do b.set({}) because the template parameter U would be undefined
    b.set(a);

    return 0;
}

解决方法

在这种情况下,您可以为 U 模板参数添加一个默认值,例如

template<typename U = T>
void set(U&& a) {
    a_=std::forward<U>(a);
}

现在如果它可以推导出类型,比如 {} 没有类型,那么它会回退使用 T 作为 U 的类型。