假设我有一个类
template <typename T>
class A {
public:
template <typename V>
void f(std::tr1::shared_ptr<const std::vector<V> > v1,
std::tr1::shared_ptr<const std::vector<float> > v2) {}
};
以下内容无法编译:
A<string> a;
std::tr1::shared_ptr<std::vector<float> > v1(new std::vector<float>());
std::tr1::shared_ptr<std::vector<float> > v2(new std::vector<float>());
a.f(v1, v2);
编译器错误是:
error: no matching function for call to 'A<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::f(std::tr1::shared_ptr<std::vector<float, std::allocator<float> > >&, std::tr1::shared_ptr<std::vector<float, std::allocator<float> > >&)'
编译器无法使 std::tr1::shared_ptr; >
进入
std::tr1::shared_ptr > 对于第一个参数。但它可以用于第二个(非模板参数)。
解决此问题的一种方法是更改对 f() 的调用,像这样调用 f(...)
。
另一个解决方案是将 v1 声明为 const vector 的 shared_ptr。
- 为什么模板实例化的行为在这里如此不同?
- 我对将
shared_ptr
作为方法参数的理解是,该方法不能更改 shared_ptr
所指向的内容。如果我们将 shared_ptr
更改为原始指针,将 v1
、v2
更改为指向 vector
的原始指针,则代码会编译得很好。 shared_ptr
是什么破坏了模板推导?
Suppose I have a class
template <typename T>
class A {
public:
template <typename V>
void f(std::tr1::shared_ptr<const std::vector<V> > v1,
std::tr1::shared_ptr<const std::vector<float> > v2) {}
};
The following does not compile:
A<string> a;
std::tr1::shared_ptr<std::vector<float> > v1(new std::vector<float>());
std::tr1::shared_ptr<std::vector<float> > v2(new std::vector<float>());
a.f(v1, v2);
The compiler error is:
error: no matching function for call to 'A<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::f(std::tr1::shared_ptr<std::vector<float, std::allocator<float> > >&, std::tr1::shared_ptr<std::vector<float, std::allocator<float> > >&)'
The compiler could not make std::tr1::shared_ptr<std::vector<float> >
into
std::tr1::shared_ptr<const std::vector<float> >
for the first argument. Yet it could for the second (non-template argument).
One solution to this is to change the call to f(), call it like this f<float>(...)
.
Another solution is to declare v1 as shared_ptr to const vector<float>.
- Why is template instantiation behaving so differently here?
- My understanding of having a
shared_ptr<const T>
as argument to a method is that the method cannot change what the shared_ptr
is pointing to. If we change the shared_ptr
s to raw pointers and v1
, v2
as raw pointers to vectors
, then the code will compile fine. What is it about shared_ptr
s that breaks template deduction?
发布评论
评论(2)
相关类型?
如您所知,
T*
和const T*
是相关类型。从第一个到第二个有一个标准转换(资格转换)。首先,您必须意识到
A
和A
不是一般相关类型。这些类型可能有不同的大小、表示形式和用途。可以定义其中之一,但不能定义另一个。特别是,
A
不是 const 限定的A
,因此两者之间不存在限定转换,并且 C++ 不够灵活声明的用户定义的限定转换。 (用户不能声明任何标准转换,只能声明用户定义的转换 - 用户定义的转换不是标准转换。)因此用户定义的类型与基本类型有根本的不同:它们不能以这种方式关联基本类型是。
shared_ptr<>
shared_ptr<>
旨在形成一系列兼容类型:shared_ptr
可以隐式转换为shared_ptr
当且仅当T*
可以隐式转换为U*
。特别是,shared_ptr
可隐式转换为shared_ptr
。它也可以隐式转换为shared_ptr
,所以道理是一样的。由于类型
shared_ptr
和shared_ptr
没有以任何特殊方式相关,因此从shared_ptr
到的转换code>shared_ptr
与shared_ptr
没有区别shared_ptr
。这些只是两种不同的转换,但在任何上下文中都不能被视为“首选”,这与从T*
到const T*
的转换(rank = 完全匹配)不同。优于从T*
到void*
的转换(排名 = Conversion)。函数模板
推导模板函数参数上允许一些标准转换:
但是正如我们所见,
shared_ptr<>
类型之间不存在此类转换。这意味着,即使允许编译器枚举模板参数的所有可能类型,以将函数模板转换
为无限的函数原型集:
除非有完全匹配,否则您将无法调用函数:给定 声明
在
f
原型集合中的中,存在:因此对
f (d)
的调用将是不明确的,因为这两个候选者都涉及不同的用户定义转换。Related types?
As you know,
T*
andconst T*
are related types. There is a standard conversion from the first to the second (qualification conversion).First, you have to realise that
A<T>
andA<const T>
are not in general related types. These type could have different size, representation, and purpose. One could be defined but not the other.In particular,
A<const T>
is not a const qualifiedA<T>
, so there is no qualification-conversion between the two, and C++ is not flexible enough to declared user-defined qualification-conversions. (A user cannot declare any standard conversion, only user-defined conversion - user-defined conversion are not standard conversions.)So user-defined types are fundamentally different from fundamental types: they cannot be related the way fundamental types are.
shared_ptr<>
shared_ptr<>
is designed to form a family of compatible types:shared_ptr<T>
is implicitly convertible toshared_ptr<U>
iffT*
is implicitly convertible toU*
. In particular,shared_ptr<T>
is implicitly convertible toshared_ptr<const T>
. It is also implicitly convertible toshared_ptr<void>
, so the same reason.Because types
shared_ptr<const T>
andshared_ptr<T>
are not related in any special way, the conversion fromshared_ptr<T>
toshared_ptr<const T>
is not distinguished fromshared_ptr<T>
toshared_ptr<void>
. These are just two different conversions, but neither can be considered "preferred" in any context, unlike the conversion fromT*
toconst T*
(rank = Exact match) which is preferred over conversion fromT*
tovoid*
(rank = Conversion).Function templates
Some standard conversions are allowed on deduced templates function arguments:
But as we have seen, no such conversions exist between
shared_ptr<>
types.This means that even if the compiler was allowed to enumerate all possible types for a template parameter to turn a function template
into an infinite set of functions prototypes:
unless you have an exact match, you would not be able to call a function: given the declarations
among the set of
f
prototypes, there is:so a call to
f (d)
would be ambiguous as both of these candidates involve different user-defined conversions.shared_ptr
可通过转换构造函数隐式转换为shared_ptr
。不幸的是,这样的转换不能在模板参数推导过程中使用。为了使参数推导成功,参数的类型必须与参数的类型完全匹配;不使用大多数转换,包括用户定义的转换。
只允许一些非常基本的转换,包括数组到指针的衰减和函数到函数指针的转换(由于函数参数不能是数组类型或函数类型,因此这些转换不会导致混乱)。此外,顶级 const 和 volatile 限定符被完全忽略。
A
shared_ptr<T>
is implicitly convertible to ashared_ptr<const T>
via a converting constructor. Unfortunately, such conversions cannot be used during template argument deduction.In order for argument deduction to succeed, the type of the argument has to match the type of the parameter exactly; most conversions, including user-defined conversions, are not used.
Only a few very basic conversions are allowed, including array-to-pointer decay and function-to-function-pointer conversion (since no function parameter can be of array type or function type, these conversions cannot lead to confusion). In addition, top-level const- and volatile- qualifiers are wholly ignored.