std::variant
has a constructor that accepts std::in_place_t<Type>, Args &&...
arguments that results in in-place construction.
{
std::cout << "in_place_type:\n";
const auto var = std::variant<callable>(std::in_place_type<callable>);
std::cout << "finished\n";
}
I wonder if it is somehow possible to in-place construct given a Factory object:
{
std::cout << "by factory:\n";
const auto var = std::variant<callable>{[] ()-> callable {return {}; }()};
std::cout << "finished\n";
}
https://godbolt.org/z/rY5WG1hGn
#include <variant>
#include <iostream>
int main(int, char **)
{
struct callable
{
callable()
{
std::cout << "callable()" << std::endl;
}
~callable()
{
std::cout << "~callable()" << std::endl;
}
};
{
std::cout << "in_place_type:\n";
const auto var = std::variant<callable>(std::in_place_type<callable>);
std::cout << "finished\n";
}
std::cout << '\n';
{
std::cout << "by factory:\n";
const auto var = std::variant<callable>{[] ()-> callable {return {}; }()};
std::cout << "finished\n";
}
}
I think it does not work in this case because std::variant(T &&t)
constructor is used with the factory, and it can not use copy elision.
I tried to elaborate on HTNW's answer (create an onbject from arguments), but get a compiler error:
#include <variant>
#include <tuple>
struct to_construct {
// must NOT exist
// template<typename F>
// to_construct(initializer<F>) { std::cout << "Foiled!\n"; }
// or (more likely)
// template<typename T>
// to_construct(T) { std::cout << "Foiled again!\n"; }
to_construct() = default;
to_construct(to_construct&&) = delete;
to_construct(to_construct const&) = delete;
};
#include <iostream>
struct callable
{
callable(int i)
{
std::cout << "callable():" << i << std::endl;
}
~callable()
{
std::cout << "~callable()" << std::endl;
}
};
template<typename T>
struct box {
T x;
template<typename F>
box(F f)
: x(f())
{}
};
template<typename F>
struct initializer {
F init;
operator auto() {
return init();
}
};
template<typename F>
initializer(F) -> initializer<F>;
template <typename ... Types, typename Factory, typename ... Args>
std::variant<box<Types>...> variant_from(Factory &&f, Args &&... args)
{
return {
initializer{
[tupleArgs = std::forward_as_tuple(args...),
f = std::forward<Factory>(f)](){
return std::apply(f, tupleArgs);
}
}
};
}
int main()
{
{
const auto var =
std::variant<to_construct>(initializer{
[]() -> to_construct {
std::cout << "Success\n";
return {};
}
});
}
{
const auto var = variant_from<callable>([](int i) { return callable(i);}, 42);
}
}
<source>: In instantiation of 'box<T>::box(F) [with F = initializer<variant_from<callable, main()::<lambda(int)>, int>(main()::<lambda(int)>&&, int&&)::<lambda()> >; T = callable]':
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/variant:283:4: required from 'constexpr std::__detail::__variant::_Uninitialized<_Type, false>::_Uninitialized(std::in_place_index_t<0>, _Args&& ...) [with _Args = {initializer<variant_from<callable, main()::<lambda(int)>, int>(main()::<lambda(int)>&&, int&&)::<lambda()> >}; _Type = box<callable>]'
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/variant:385:4: required from 'constexpr std::__detail::__variant::_Variadic_union<_First, _Rest ...>::_Variadic_union(std::in_place_index_t<0>, _Args&& ...) [with _Args = {initializer<variant_from<callable, main()::<lambda(int)>, int>(main()::<lambda(int)>&&, int&&)::<lambda()> >}; _First = box<callable>; _Rest = {}]'
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/variant:460:4: required from 'constexpr std::__detail::__variant::_Variant_storage<false, _Types ...>::_Variant_storage(std::in_place_index_t<_Np>, _Args&& ...) [with long unsigned int _Np = 0; _Args = {initializer<variant_from<callable, main()::<lambda(int)>, int>(main()::<lambda(int)>&&, int&&)::<lambda()> >}; _Types = {box<callable>}]'
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/variant:557:20: required from 'constexpr std::__detail::__variant::_Variant_base<_Types>::_Variant_base(std::in_place_index_t<_Np>, _Args&& ...) [with long unsigned int _Np = 0; _Args = {initializer<variant_from<callable, main()::<lambda(int)>, int>(main()::<lambda(int)>&&, int&&)::<lambda()> >}; _Types = {box<callable>}]'
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/variant:1448:57: required from 'constexpr std::variant<_Types>::variant(std::in_place_index_t<_Np>, _Args&& ...) [with long unsigned int _Np = 0; _Args = {initializer<variant_from<callable, main()::<lambda(int)>, int>(main()::<lambda(int)>&&, int&&)::<lambda()> >}; _Tp = box<callable>; <template-parameter-2-4> = void; _Types = {box<callable>}]'
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/variant:1419:27: required from 'constexpr std::variant<_Types>::variant(_Tp&&) [with _Tp = initializer<variant_from<callable, main()::<lambda(int)>, int>(main()::<lambda(int)>&&, int&&)::<lambda()> >; <template-parameter-2-2> = void; <template-parameter-2-3> = void; _Tj = box<callable>; <template-parameter-2-5> = void; _Types = {box<callable>}]'
<source>:61:5: required from 'std::variant<box<Types>...> variant_from(Factory&&, Args&& ...) [with Types = {callable}; Factory = main()::<lambda(int)>; Args = {int}]'
<source>:78:46: required from here
<source>:36:8: error: no match for call to '(initializer<variant_from<callable, main()::<lambda(int)>, int>(main()::<lambda(int)>&&, int&&)::<lambda()> >) ()'
36 | : x(f())
| ~^~
ASM generation compiler returned: 1
<source>: In instantiation of 'box<T>::box(F) [with F = initializer<variant_from<callable, main()::<lambda(int)>, int>(main()::<lambda(int)>&&, int&&)::<lambda()> >; T = callable]':
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/variant:283:4: required from 'constexpr std::__detail::__variant::_Uninitialized<_Type, false>::_Uninitialized(std::in_place_index_t<0>, _Args&& ...) [with _Args = {initializer<variant_from<callable, main()::<lambda(int)>, int>(main()::<lambda(int)>&&, int&&)::<lambda()> >}; _Type = box<callable>]'
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/variant:385:4: required from 'constexpr std::__detail::__variant::_Variadic_union<_First, _Rest ...>::_Variadic_union(std::in_place_index_t<0>, _Args&& ...) [with _Args = {initializer<variant_from<callable, main()::<lambda(int)>, int>(main()::<lambda(int)>&&, int&&)::<lambda()> >}; _First = box<callable>; _Rest = {}]'
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/variant:460:4: required from 'constexpr std::__detail::__variant::_Variant_storage<false, _Types ...>::_Variant_storage(std::in_place_index_t<_Np>, _Args&& ...) [with long unsigned int _Np = 0; _Args = {initializer<variant_from<callable, main()::<lambda(int)>, int>(main()::<lambda(int)>&&, int&&)::<lambda()> >}; _Types = {box<callable>}]'
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/variant:557:20: required from 'constexpr std::__detail::__variant::_Variant_base<_Types>::_Variant_base(std::in_place_index_t<_Np>, _Args&& ...) [with long unsigned int _Np = 0; _Args = {initializer<variant_from<callable, main()::<lambda(int)>, int>(main()::<lambda(int)>&&, int&&)::<lambda()> >}; _Types = {box<callable>}]'
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/variant:1448:57: required from 'constexpr std::variant<_Types>::variant(std::in_place_index_t<_Np>, _Args&& ...) [with long unsigned int _Np = 0; _Args = {initializer<variant_from<callable, main()::<lambda(int)>, int>(main()::<lambda(int)>&&, int&&)::<lambda()> >}; _Tp = box<callable>; <template-parameter-2-4> = void; _Types = {box<callable>}]'
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/variant:1419:27: required from 'constexpr std::variant<_Types>::variant(_Tp&&) [with _Tp = initializer<variant_from<callable, main()::<lambda(int)>, int>(main()::<lambda(int)>&&, int&&)::<lambda()> >; <template-parameter-2-2> = void; <template-parameter-2-3> = void; _Tj = box<callable>; <template-parameter-2-5> = void; _Types = {box<callable>}]'
<source>:61:5: required from 'std::variant<box<Types>...> variant_from(Factory&&, Args&& ...) [with Types = {callable}; Factory = main()::<lambda(int)>; Args = {int}]'
<source>:78:46: required from here
<source>:36:8: error: no match for call to '(initializer<variant_from<callable, main()::<lambda(int)>, int>(main()::<lambda(int)>&&, int&&)::<lambda()> >) ()'
36 | : x(f())
| ~^~
Execution build compiler returned: 1
T&&
constructor has to bind to an object, so no copy elision. – Thadstd::variant
that would take a factory object. I am just not sure if there may be any workarounds. So the answer saying "it is not possible" would be legit – Miningbox
you are not supposed to useinitializer
as well as explained in the answer. There is no need to use the init-captures invariant_from
. Just[&]
will be fine. – Luht