Constructing a value through two implicit constructors?
TL; DR : I have two templated classes Outer
and Inner
. Inner<X>
may be implicitly constructed from X
, or Outer<Y>
may be implicitly constructed from Y
. Should it 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:
Outer<Inner<SomeType>> DoSomethingWorks() {
SomeType value;
return Inner<SomeType>(value);
}
It works. Can you expect it DoSomethingFails
to work? If not, why not? And can the code be changed the way it works DoSomethingFails
?
source to share
In the first example, two custom conversions are required to compile & mdash. SomeType -> Inner -> Outer
... However, at most one user-defined transformation can be applied implicitly.
Quote N3337, §12.3 [class.conv]
1 The type of conversion of class objects can be specified by constructors and conversion functions. These conversions are called custom conversions and are used for implicit conversions (Section 4), for initialization (8.5), and for explicit conversions (5.4, 5.2.9).
4 At most 1 custom conversion (constructor or conversion function) is implicitly applied to a single value.
If the goal is to avoid being mentioned Inner<SomeType>
in the return statement, you can use list initialization.
Outer<Inner<SomeType>> DoSomethingWorks2() {
SomeType value;
return {std::move(value)};
}
source to share