c++ - 为什么此自定义类型特征无法编译
问题描述
我不确定我在下面做错了什么。我正在尝试编写一个特征 can_visit并使用 std::void_t 和 sfinae 的标准模式,但它不会编译并一直告诉我包含std::visit表达式的 decltype 语句中有错误。
如果我将 #47 处的行替换为
std::cout << can_visit<ABCVis,ABC>::value << std::endl;
它编译但违背了目的。
std::cout << can_visit<ABVis,ABC>::value << std::endl;
应该输出 0 而不是编译失败
#include <variant>
#include <iostream>
template <class TVisitor, class TVariant, class=void>
struct can_visit: std::false_type {};
template <class TVisitor, class TVariant >
struct can_visit
<
TVisitor,
TVariant,
std::void_t<
decltype(std::visit(
std::declval<TVisitor&>(),
std::declval<TVariant&>()
)
)
>
>
: std::true_type {};
struct A{};
struct B{};
struct C{};
using ABC = std::variant<A,B,C>;
using AB = std::variant<A,B>;
struct ABCVis {
void operator()(A const & a){};
void operator()(B const & a){};
void operator()(C const & a){};
};
struct ABVis {
void operator()(A const & a){};
void operator()(B const & a){};
};
int main(){
std::cout << can_visit<ABVis,ABC>::value << std::endl;
}
完整的错误消息在这里,但可以在https://godbolt.org/z/Gz4Ef4x1n上的 Godbolt 上执行
In file included from <source>:1:
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:1020:11: error: no matching function for call to '__invoke'
return std::__invoke(std::forward<_Visitor>(__visitor),
^~~~~~~~~~~~~
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:1031:29: note: in instantiation of member function 'std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<std::__detail::__variant::__deduce_visit_result<void> (*)(ABVis &, std::variant<A, B, C> &)>, std::integer_sequence<unsigned long, 2>>::__visit_invoke' requested here
{ return _Array_type{&__visit_invoke}; }
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:976:48: note: in instantiation of member function 'std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<std::__detail::__variant::__deduce_visit_result<void> (*)(ABVis &, std::variant<A, B, C> &)>, std::integer_sequence<unsigned long, 2>>::_S_apply' requested here
std::index_sequence<__indices..., __index>>::_S_apply();
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:955:7: note: in instantiation of function template specialization 'std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<std::__detail::__variant::__deduce_visit_result<void> (*)(ABVis &, std::variant<A, B, C> &), 3>, std::integer_sequence<unsigned long>>::_S_apply_single_alt<false, 2, std::__detail::__variant::_Multi_array<std::__detail::__variant::__deduce_visit_result<void> (*)(ABVis &, std::variant<A, B, C> &)>>' requested here
(_S_apply_single_alt<false, __var_indices>(
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:940:2: note: in instantiation of function template specialization 'std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<std::__detail::__variant::__deduce_visit_result<void> (*)(ABVis &, std::variant<A, B, C> &), 3>, std::integer_sequence<unsigned long>>::_S_apply_all_alts<0, 1, 2>' requested here
_S_apply_all_alts(
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:1042:59: note: in instantiation of member function 'std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<std::__detail::__variant::__deduce_visit_result<void> (*)(ABVis &, std::variant<A, B, C> &), 3>, std::integer_sequence<unsigned long>>::_S_apply' requested here
= __gen_vtable_impl<_Array_type, std::index_sequence<>>::_S_apply();
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:1699:45: note: in instantiation of static data member 'std::__detail::__variant::__gen_vtable<std::__detail::__variant::__deduce_visit_result<void>, ABVis &, std::variant<A, B, C> &>::_S_vtable' requested here
_Result_type, _Visitor&&, _Variants&&...>::_S_vtable;
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:1718:19: note: in instantiation of function template specialization 'std::__do_visit<std::__detail::__variant::__deduce_visit_result<void>, ABVis &, std::variant<A, B, C> &>' requested here
return std::__do_visit<_Tag>(std::forward<_Visitor>(__visitor),
^
<source>:13:23: note: in instantiation of function template specialization 'std::visit<ABVis &, std::variant<A, B, C> &>' requested here
decltype(std::visit(
^
<source>:47:18: note: during template argument deduction for class template partial specialization 'can_visit<TVisitor, TVariant>' [with TVisitor = ABVis, TVariant = std::variant<A, B, C>]
std::cout << can_visit<ABVis,ABC>::value << std::endl;
^
<source>:47:18: note: in instantiation of template class 'can_visit<ABVis, std::variant<A, B, C>>' requested here
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/bits/invoke.h:89:5: note: candidate template ignored: substitution failure [with _Callable = ABVis &, _Args = <C &>]: no type named 'type' in 'std::__invoke_result<ABVis &, C &>'
__invoke(_Callable&& __fn, _Args&&... __args)
^
In file included from <source>:1:
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:1041:36: error: constexpr variable '_S_vtable' must be initialized by a constant expression
static constexpr _Array_type _S_vtable
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:1699:45: note: in instantiation of static data member 'std::__detail::__variant::__gen_vtable<std::__detail::__variant::__deduce_visit_result<void>, ABVis &, std::variant<A, B, C> &>::_S_vtable' requested here
_Result_type, _Visitor&&, _Variants&&...>::_S_vtable;
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:1718:19: note: in instantiation of function template specialization 'std::__do_visit<std::__detail::__variant::__deduce_visit_result<void>, ABVis &, std::variant<A, B, C> &>' requested here
return std::__do_visit<_Tag>(std::forward<_Visitor>(__visitor),
^
<source>:13:23: note: in instantiation of function template specialization 'std::visit<ABVis &, std::variant<A, B, C> &>' requested here
decltype(std::visit(
^
<source>:47:18: note: during template argument deduction for class template partial specialization 'can_visit<TVisitor, TVariant>' [with TVisitor = ABVis, TVariant = std::variant<A, B, C>]
std::cout << can_visit<ABVis,ABC>::value << std::endl;
^
<source>:47:18: note: in instantiation of template class 'can_visit<ABVis, std::variant<A, B, C>>' requested here
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:955:7: note: subexpression not valid in a constant expression
(_S_apply_single_alt<false, __var_indices>(
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:940:2: note: in call to '_S_apply_all_alts(__vtable, {})'
_S_apply_all_alts(
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:1042:4: note: in call to '_S_apply()'
= __gen_vtable_impl<_Array_type, std::index_sequence<>>::_S_apply();
^
2 errors generated.
ASM generation compiler returned: 1
In file included from <source>:1:
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:1020:11: error: no matching function for call to '__invoke'
return std::__invoke(std::forward<_Visitor>(__visitor),
^~~~~~~~~~~~~
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:1031:29: note: in instantiation of member function 'std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<std::__detail::__variant::__deduce_visit_result<void> (*)(ABVis &, std::variant<A, B, C> &)>, std::integer_sequence<unsigned long, 2>>::__visit_invoke' requested here
{ return _Array_type{&__visit_invoke}; }
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:976:48: note: in instantiation of member function 'std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<std::__detail::__variant::__deduce_visit_result<void> (*)(ABVis &, std::variant<A, B, C> &)>, std::integer_sequence<unsigned long, 2>>::_S_apply' requested here
std::index_sequence<__indices..., __index>>::_S_apply();
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:955:7: note: in instantiation of function template specialization 'std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<std::__detail::__variant::__deduce_visit_result<void> (*)(ABVis &, std::variant<A, B, C> &), 3>, std::integer_sequence<unsigned long>>::_S_apply_single_alt<false, 2, std::__detail::__variant::_Multi_array<std::__detail::__variant::__deduce_visit_result<void> (*)(ABVis &, std::variant<A, B, C> &)>>' requested here
(_S_apply_single_alt<false, __var_indices>(
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:940:2: note: in instantiation of function template specialization 'std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<std::__detail::__variant::__deduce_visit_result<void> (*)(ABVis &, std::variant<A, B, C> &), 3>, std::integer_sequence<unsigned long>>::_S_apply_all_alts<0, 1, 2>' requested here
_S_apply_all_alts(
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:1042:59: note: in instantiation of member function 'std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<std::__detail::__variant::__deduce_visit_result<void> (*)(ABVis &, std::variant<A, B, C> &), 3>, std::integer_sequence<unsigned long>>::_S_apply' requested here
= __gen_vtable_impl<_Array_type, std::index_sequence<>>::_S_apply();
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:1699:45: note: in instantiation of static data member 'std::__detail::__variant::__gen_vtable<std::__detail::__variant::__deduce_visit_result<void>, ABVis &, std::variant<A, B, C> &>::_S_vtable' requested here
_Result_type, _Visitor&&, _Variants&&...>::_S_vtable;
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:1718:19: note: in instantiation of function template specialization 'std::__do_visit<std::__detail::__variant::__deduce_visit_result<void>, ABVis &, std::variant<A, B, C> &>' requested here
return std::__do_visit<_Tag>(std::forward<_Visitor>(__visitor),
^
<source>:13:23: note: in instantiation of function template specialization 'std::visit<ABVis &, std::variant<A, B, C> &>' requested here
decltype(std::visit(
^
<source>:47:18: note: during template argument deduction for class template partial specialization 'can_visit<TVisitor, TVariant>' [with TVisitor = ABVis, TVariant = std::variant<A, B, C>]
std::cout << can_visit<ABVis,ABC>::value << std::endl;
^
<source>:47:18: note: in instantiation of template class 'can_visit<ABVis, std::variant<A, B, C>>' requested here
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/bits/invoke.h:89:5: note: candidate template ignored: substitution failure [with _Callable = ABVis &, _Args = <C &>]: no type named 'type' in 'std::__invoke_result<ABVis &, C &>'
__invoke(_Callable&& __fn, _Args&&... __args)
^
In file included from <source>:1:
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:1041:36: error: constexpr variable '_S_vtable' must be initialized by a constant expression
static constexpr _Array_type _S_vtable
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:1699:45: note: in instantiation of static data member 'std::__detail::__variant::__gen_vtable<std::__detail::__variant::__deduce_visit_result<void>, ABVis &, std::variant<A, B, C> &>::_S_vtable' requested here
_Result_type, _Visitor&&, _Variants&&...>::_S_vtable;
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:1718:19: note: in instantiation of function template specialization 'std::__do_visit<std::__detail::__variant::__deduce_visit_result<void>, ABVis &, std::variant<A, B, C> &>' requested here
return std::__do_visit<_Tag>(std::forward<_Visitor>(__visitor),
^
<source>:13:23: note: in instantiation of function template specialization 'std::visit<ABVis &, std::variant<A, B, C> &>' requested here
decltype(std::visit(
^
<source>:47:18: note: during template argument deduction for class template partial specialization 'can_visit<TVisitor, TVariant>' [with TVisitor = ABVis, TVariant = std::variant<A, B, C>]
std::cout << can_visit<ABVis,ABC>::value << std::endl;
^
<source>:47:18: note: in instantiation of template class 'can_visit<ABVis, std::variant<A, B, C>>' requested here
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:955:7: note: subexpression not valid in a constant expression
(_S_apply_single_alt<false, __var_indices>(
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:940:2: note: in call to '_S_apply_all_alts(__vtable, {})'
_S_apply_all_alts(
^
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/variant:1042:4: note: in call to '_S_apply()'
= __gen_vtable_impl<_Array_type, std::index_sequence<>>::_S_apply();
^
2 errors generated.
Execution build compiler returned: 1
对于上下文,它与此代码没有太大区别 https://godbolt.org/z/aa5cqWhz8
#include <variant>
#include <iostream>
template <class A, class B, class=void>
struct can_add: std::false_type {};
template <class A, class B >
struct can_add
<
A,
B,
std::void_t<
decltype(std::declval<A>()+std::declval<B>()
)
>
>
: std::true_type {};
int main(){
std::cout << can_add<int,int>::value << std::endl;
std::cout << can_add<int,std::string>::value << std::endl;
}
编译和输出
1
0
正如预期的那样。
解决方案
检测习语只能判断给定的表达式是否有效。
和表达
std::visit(std::declval<TVisitor&>(), std::declval<TVariant&>())
对所有TVisitor
and都有效TVariant
,因为std::visit
它是一个不受限制的模板1。
但是,相应的实例化可能无效,但这不是您可以直接检测到的。
相反,您必须手动检测可能使实例化无效的条件。您的类型特征应该确定是否可以使用给定变体中的所有类型调用给定访问者。
像这样,例如:
template <class TVisitor, class TVariant>
struct can_visit;
template <class TVisitor, class... TTypes>
struct can_visit<TVisitor, std::variant<TTypes...>> {
constexpr static bool value = (std::is_invocable_v<TVisitor, TTypes> && ...);
};
https://godbolt.org/z/fz7e5W7ah
推荐阅读
- swagger - 如何告诉 dropwizard-swagger/swagger-ui 资源方法上没有请求正文?
- sharepoint-2013 - Sharepoint 2013:创建一个脚本以在我添加新字段时更新列表视图
- grails - 查找带有“+”的电子邮件时,通过电子邮件获取失败
- docker - 使用 env_file 在 docker-compose.yml 中设置构建参数
- scala - Gatling 负载均衡 IP 哈希 Nginx
- ruby-on-rails - Rails Sprockets 文件使用本地清单作为摘要而不是资产主机版本
- algorithm - 在矩阵中找到三个总和最大的单元格
- java - 如何在执行 order by 时避免结果集关闭错误
- python - asyncio create_task 永远运行
- c# - 添加了 Unity DI 框架,现在得到错误“UmbracoAuthorizeAttribute 类型有多个长度为 1 的构造函数。无法消除歧义。”