我在模板扣除/类型转换方面遇到问题。以下代码无法编译:
template <typename Type>
struct A
{
void DoA()
{
}
};
struct B : public A<B>
{
void DoB()
{
}
};
template <typename T>
void DoSmth(const std::shared_ptr<A<T>> &p)
{
p->DoA();
}
int _tmain(int argc, _TCHAR* argv[])
{
std::shared_ptr<B> pb(new B);
DoSmth(pb);
//std::shared_ptr<A<B>> pa(pb);
//DoSmth(pa);
return 0;
};
MSVC错误如下:
error C2664: 'void DoSmth<B>(const std::shared_ptr<A<B>> &)' : cannot convert argument 1 from 'std::shared_ptr<B>' to 'const std::shared_ptr<A<B>> &'
Binding to reference with added qualification
followed by
Call to constructor 'std::shared_ptr<A<B>>::shared_ptr<B,void>(const std::shared_ptr<B> &) throw()'
c:\program files (x86)\microsoft visual studio 12.0\vc\include\memory(531) : see declaration of 'std::shared_ptr<A<B>>::shared_ptr'
followed by
Binding to reference
海湾合作委员会错误:
prog.cpp:28:11: error: no matching function for call to ‘DoSmth(std::shared_ptr<B>&)’
DoSmth(pb);
^
prog.cpp:21:6: note: candidate: template<class T> void DoSmth(const std::shared_ptr<A<T> >&)
void DoSmth(const std::shared_ptr<A<T>> &p)
^~~~~~
prog.cpp:21:6: note: template argument deduction/substitution failed:
prog.cpp:28:11: note: mismatched types ‘A<T>’ and ‘B’
DoSmth(pb);
^
注释代码(当手动完成转换时)不会发生问题,如果i_a
不是模板类,也不会发生问题。我想知道为什么编译器不能进行转换,如果(根据错误信息)它已经推断出模板类型(这样它应该等同于注释代码)。
在不改变函数的参数类型(我迫切需要它为A<T>
)的情况下,我可以做些什么吗?请注意,shared_ptr
类仅用于说明问题,我实际上使用了另一个智能指针类,我可以轻松更改(如果需要在那里进行更改)。
请注意,如果使用原始指针而不是智能指针,一切都像魅力一样!
答案 0 :(得分:5)
这里的问题是void DoSmth(const std::shared_ptr<A<T>> &p)
T
是一种依赖类型,无法推断出来。所以我们需要给编译器一些帮助。值得庆幸的是,我们可以使用SFINAE和std::is_base_of
来约束模板。如果我们使用
template <typename T>
void DoSmth(const std::shared_ptr<T> &p)
然后T
现在是可推导的,但是这个函数将接受任何不是我们想要的共享指针。我们只需要一个T
A<T>
或从中派生的东西。使用std::enable_if
和std::is_base_of
,我们可以像
template <typename T, typename = typename std::enable_if<std::is_base_of<A<T>, T>::value>::type>
void DoSmth(const std::shared_ptr<T> &p)
{
p->DoA();
}
现在我们可以将std::shared_ptr<B>
传递给函数而无需做任何额外的事情。下面是一个显示它正常工作的示例,它也拒绝了shared_ptr
非派生类型:
#include <type_traits>
#include <memory>
template <typename Type>
struct A
{
void DoA()
{
}
};
struct B : public A<B>
{
void DoB()
{
}
};
struct Foo {};
template <typename T, typename = typename std::enable_if<std::is_base_of<A<T>, T>::value>::type>
void DoSmth(const std::shared_ptr<T> &p)
{
p->DoA();
}
int main()
{
std::shared_ptr<B> pb(new B);
DoSmth(pb); // this compiles
std::shared_ptr<Foo> pf(new Foo);
DoSmth(pf); // this will generate a compiler error
//std::shared_ptr<A<B>> pa(pb);
//DoSmth(pa);
return 0;
}
答案 1 :(得分:2)
您可以明确指定类型。
int main()
{
std::shared_ptr<B> pb(new B);
DoSmth<B>(pb);
//-----^
}