类型推导失败:派生模板的 shared_ptr 到基模板作为函数参数

type deduction fail: shared_ptr of derived template to base template as function argument

这里我声明了两个模板类:A和B,B派生自A:

template<typename T>
class A {
public:
    int a;
    T t;
};

template<typename T>
class B : public A<T> {
public:
    int b;
};

然后我做了一个shared_ptr<B<T>>赋值给shared_ptr<A<T>>,没问题:

auto b = std::make_shared<B<std::string>>();
std::shared_ptr<A<std::string>> a = b;

这里我声明了一个模板函数接受shared_ptr A<T>

template<typename T>
void proc(std::shared_ptr<A<T>> &a) {
    std::cout << a->a << std::endl;
}

它接受 a 作为参数,但拒绝 b

proc<std::string>(a); // OK
proc<std::string>(b); // template argument deduction/substitution failed
                      // cannot convert 'b' (type 'std::shared_ptr<B<std::__cxx11::basic_string<char> > >') to type 'std::shared_ptr<A<std::__cxx11::basic_string<char> > >&'

我使用 g++ 作为带有 -std=c++11 的编译器。

这个错误给我带来了很多问题,我该如何优雅地解决这个问题?

给定 proc<std::string>(b);b 需要转换为 std::shared_ptr<A<std::string>>。这意味着将构造一个临时 std::shared_ptr<A<std::string>>,然后传递给 procproc 的参数类型是对非常量的左值引用,即 std::shared_ptr<A<T>> &,不能绑定到临时对象。

您可以将参数类型更改为对const 的左值引用,这可以绑定到临时对象。例如

template<typename T>
void proc(const std::shared_ptr<A<T>> &a) {
//        ^^^^^
    std::cout << a->a << std::endl;
}

首先,你做一个shared_ptr叫:

auto b = std::make_shared<B<std::string>>();

属于 std::shared_ptr<B<std::string>> 类型,

std::shared_ptr<A<std::string>> a = b;

类型为 std::shared_ptr<A<std::string>>...

然而,在您的函数参数中,您有:

void proc(std::shared_ptr<A<T>> &a)

只指向Ashared_ptr,而不是B,所以很明显 B 不会变成 A...


解决方案是从函数定义中删除 alvalue 引用,例如:

void proc(std::shared_ptr<A<T>> a)

所以,它不是指AB可以很容易地转换为A 在函数调用期间...


编辑: 添加了解释...

解释:

还记得指针吗?来自 C...yes,它们执行 与引用相同的功能:

// Compilable both in C and C++...
int add(int a, int b, int * more_than_3) {
    int const result = a + b;
    if (result > 3)
        *more_than_3 = 1;
    return result;
}

是的,这些将在 C 中实现 pseudo-return types 的功能。喜欢:

// Compilable both in C and C++...
int main(void) {
    int more_3;
    int const res = add(2, 3, &more_3);
    printf("Sum of 2 + 3 is %i\n", res);
    if (more_3)
        printf("Given two numbers' sum is more than 3");
}

这里,传递了一个额外的参数,它接受 address of 一个变量引用也做同样的事情,他们分享他们的地址引用它们的变量...)

记住,引用和指针存储其中另一个变量的地址...

这可能就是为什么他们让 运算符的 地址 (&) 也作用于 references in C++...


另外,不需要,但是 在这里发布的答案有效,因为:

void proc(std::shared_ptr<A<T>> const &a)

使用常量引用常量表达式的引用,而不是变量,所以它们是否不匹配也没关系(AB