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?
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]
If the goal is to avoid having to mention
Inner<SomeType>
in the return statement, you can use list initialization.