问题
TLDR: I have two templatized classes Outer
and Inner
. Inner<X>
can be implicitly constructed from X
, and Outer<Y>
can be implicitly constructed from Y
. Should Outer<Inner<X>> = X()
work?
More details:
Suppose I have the following two classes:
template<typename T>
class Inner {
public:
Inner(const T& value) {}
Inner(T&& value) {}
};
template<typename T>
class Outer {
public:
Outer(const T& value) {}
Outer(T&& value) {}
};
Consider the following function:
struct SomeType{};
Outer<Inner<SomeType>> DoSomethingFails() {
SomeType value;
return value;
}
g++ complains:
no viable conversion from 'SomeType' to 'Outer<Inner<SomeType> >'
note: candidate constructor not viable: no known conversion from 'SomeType' to 'const Inner<SomeType> &' for 1st argument
But if I do the following instead:
Outer<Inner<SomeType>> DoSomethingWorks() {
SomeType value;
return Inner<SomeType>(value);
}
It works. Is it reasonable to expect DoSomethingFails
to work? If not, why? And can the code be changed in a way that DoSomethingFails
works?
回答1:
Your first example requires two user defined conversions to compile — SomeType -> Inner -> Outer
. However, at most one user defined conversion can be applied implicitly.
Quoting N3337, §12.3 [class.conv]
1 Type conversions of class objects can be specified by constructors and by conversion functions. These conversions are called user-defined conversions and are used for implicit type conversions (Clause 4), for initialization (8.5), and for explicit type conversions (5.4, 5.2.9).
4 At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single value.
If the goal is to avoid having to mention Inner<SomeType>
in the return statement, you can use list initialization.
Outer<Inner<SomeType>> DoSomethingWorks2() {
SomeType value;
return {std::move(value)};
}
来源:https://stackoverflow.com/questions/30315254/constructing-a-value-through-two-implicit-constructors