类型推导失败:派生模板的 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>>
,然后传递给 proc
。 proc
的参数类型是对非常量的左值引用,即 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)
只指向A的shared_ptr
,而不是B,所以很明显 B 不会变成 A...
解决方案是从函数定义中删除 a
的 lvalue 引用,例如:
void proc(std::shared_ptr<A<T>> a)
所以,它不是指A,B可以很容易地转换为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)
使用常量引用,对常量表达式的引用,而不是变量,所以它们是否不匹配也没关系(A
和B
)
这里我声明了两个模板类: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>>
,然后传递给 proc
。 proc
的参数类型是对非常量的左值引用,即 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)
只指向A的shared_ptr
,而不是B,所以很明显 B 不会变成 A...
解决方案是从函数定义中删除 a
的 lvalue 引用,例如:
void proc(std::shared_ptr<A<T>> a)
所以,它不是指A,B可以很容易地转换为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)
使用常量引用,对常量表达式的引用,而不是变量,所以它们是否不匹配也没关系(A
和B
)