I just watched Stephan T. Lavavej talk at CppCon 2018
on \"Class Template Argument Deduction\", where at some point he incidentally says:
In
Here is at least one case:
struct foo {
template
operator T() const {
std::cout << sizeof(T) << "\n";
return {};
}
};
if you do foo f; int x = f; double y = f;
, type information will flow "backwards" to figure out what T
is in operator T
.
You can use this in a more advanced way:
template
struct tag_t {using type=T;};
template
struct deduce_return_t {
F f;
template
operator T()&&{ return std::forward(f)(tag_t{}); }
};
template
deduce_return_t(F&&)->deduce_return_t;
template
auto construct_from( Args&&... args ) {
return deduce_return_t{ [&](auto ret){
using R=typename decltype(ret)::type;
return R{ std::forward(args)... };
}};
}
so now I can do
std::vector v = construct_from( 1, 2, 3 );
and it works.
Of course, why not just do {1,2,3}
? Well, {1,2,3}
isn't an expression.
std::vector> v;
v.emplace_back( construct_from(1,2,3) );
which, admittedly, require a bit more wizardry: Live example. (I have to make the deduce return do a SFINAE check of F, then make the F be SFINAE friendly, and I have to block std::initializer_list in deduce_return_t operator T.)