【发布时间】:2020-02-02 14:19:04
【问题描述】:
我沉迷于一些星期天早些时候的 C++20 恶作剧,在玩 gcc/clang 主干概念时,我偶然发现了一个我看不到优雅解决方案的问题。考虑这段代码:
template <typename T>
concept floating_point = std::is_floating_point_v<std::decay_t<T>>;
template <typename T>
concept indexable = requires(T v)
{
{v[0]} -> floating_point;
{v[1]} -> floating_point;
{v[2]} -> floating_point;
};
template <typename T>
concept func_indexable = requires(T v)
{
{v.x()} -> floating_point;
{v.y()} -> floating_point;
{v.z()} -> floating_point;
};
template <typename T>
concept name_indexable = requires(T v)
{
{v.x} -> floating_point;
{v.y} -> floating_point;
{v.z} -> floating_point;
};
template <typename T>
concept only_name_indexable = name_indexable<T> && !indexable<T>;
template <typename T>
concept only_func_indexable = func_indexable<T> && !indexable<T> && !name_indexable<T>;
void test_indexable(indexable auto v) {
std::cout << v[0] << " " << v[1] << " " << v[2] << "\n";
}
void test_name_indexable(only_name_indexable auto v) {
std::cout << v.x << " " << v.y << " " << v.z << "\n";
}
void test_func_indexable(only_func_indexable auto v) {
std::cout << v.x() << " " << v.y() << " " << v.z() << "\n";
}
(obligatory godbolt for toying with this)https://godbolt.org/z/gyCAQn
现在考虑一个满足only_func_indexable 的结构/类:拥有x()、y() 和z() 的成员函数会立即导致name_indexable 的概念检查中出现编译错误。更准确地说:
<source>: In instantiation of 'void test_func_indexable(auto:3) [with auto:3 = func_point]':
<source>:125:26: required from here
<source>:29:6: error: 'decltype' cannot resolve address of overloaded function
29 | {v.x} -> floating_point;
这有点明显,因为.x 指的是成员函数的名称,它是decltype 中的非法表达式。另请注意,将name_indexable 的定义更改为
template <typename T>
concept name_indexable = !func_indexable<T> && requires(T v)
{
{v.x} -> floating_point;
{v.y} -> floating_point;
{v.z} -> floating_point;
};
通过惰性联合求值解决问题。
此时我的收获是:“每当我想检查一个成员变量的存在时,我必须首先提供并检查一个类似名称的成员不存在的概念函数”。
现在这感觉相当尴尬,就像 ISO 小组中的优秀人员想到了一个更优雅的解决方案一样。
在这种情况下该解决方案是什么?
最好, 理查德
【问题讨论】:
-
如果一个类型有一个名为
x的成员函数,它不应该也有一个同名的成员变量。那么为什么你需要同时检查成员函数的存在和成员变量的不存在呢? -
不确定它是否优雅,但您可以使用嵌套需求并执行类似
requires(floating_point<decltype(a.x)>)而不是{v.x} -> floating_point;之类的操作。 -
两者都没有必要存在,只需检查 only 具有成员函数的类型会导致类型错误(请参阅链接的godbolt)。考虑到这是非法的并且是实际错误,使用 decltype(a.x) 的解决方案也不应该起作用。
-
@RichardVock 我的意思是说
v.x而不是a.x它也应该像v一样工作,这取决于template context内部requires中变量的模板类型和编译错误@false,还有{v.x} -> floating_point似乎在clang主干中编译,所以我不确定是GCC本身还是clang的问题 -
@Gaurav Dhiman 据我了解,
requires(floating_point<decltype(v.x)>)是{v.x} -> floating_point;编译的内容,所以我不认为这样做有什么意义。你是完全正确的,虽然它确实在铿锵声中编译。奇怪的。如果编译错误实际上被忽略为假(如 SFINAE),那么整个问题确实会归结为编译器错误:)。
标签: c++ c++-concepts