【发布时间】:2022-09-18 01:14:47
【问题描述】:
std::variant 有一个构造函数,它接受 std::in_place_t<Type>, Args &&... 参数,导致就地构造。
{
std::cout << \"in_place_type:\\n\";
const auto var = std::variant<callable>(std::in_place_type<callable>);
std::cout << \"finished\\n\";
}
我想知道是否有可能在给定工厂对象的情况下就地构造:
{
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\";
}
}
我认为在这种情况下它不起作用,因为 std::variant(T &&t) 构造函数与工厂一起使用,并且不能使用复制省略。
我试图详细说明HTNW\ 的答案(从参数创建一个对象),但得到一个编译器错误:
#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&&构造函数必须绑定到一个对象,所以没有复制省略。 -
@NathanOliver 我猜。
std::variant没有构造函数重载,它将采用工厂对象。我只是不确定是否有任何解决方法。所以说“不可能”的答案是合法的 -
如果您使用的是
box,则不应使用initializer,并在答案中进行了解释。无需使用variant_from中的初始化捕获。只需[&]就可以了。
标签: c++ templates c++17 copy-elision