作者:潇洒看不惯_185 | 来源:互联网 | 2022-11-03 14:36
如果满足以下条件,则以下代码可完美编译:
我不包括
或
我命名operator==
为alp::operator==
。
我想有一个问题
和operator==
,但我不知道是什么。
我用gcc 7.3.0,clang ++-6.0和goldbolt编译代码。总是相同的错误。
问题在于编译器正在尝试将to的参数转换operator==
为const_iterator
,但是为什么呢?(我想编译器看不到我的版本,而是在operator==
寻找其他版本)。
#include
#include // comment and compile
namespace alp{
template
struct Iterator {
using const_iterator = Iterator;
operator const_iterator() { return const_iterator{}; }
};
template
bool operator==(const Iterator& x, const Iterator& y)
{ return true;}
}// namespace
struct Func{
int& operator()(int& p) const {return p;}
};
template
struct View_iterator_base{
using return_type = decltype(View{}(*It{}));
using const_iterator =
View_iterator_base::const_iterator, Func>;
};
using view_it =
alp::Iterator::iterator, Func>>;
int main()
{
view_it p{};
view_it z{};
bool x = operator==(z, p); // only compiles if you remove
bool y = alp::operator==(z,p); // always compile
}
错误信息:
yy.cpp: In instantiation of ‘struct View_iterator_base<__gnu_cxx::__normal_iterator >, Func>’:
yy.cpp:9:73: required from ‘struct alp::Iterator >, Func> >’
yy.cpp:44:29: required from here
yy.cpp:28:42: error: no match for call to ‘(Func) (const int&)’
using return_type = decltype(View{}(*It{}));
~~~~~~^~~~~~~
yy.cpp:22:10: note: candidate: int& Func::operator()(int&) const
int& operator()(int& p) const {return p;}
^~~~~~~~
yy.cpp:22:10: note: conversion of argument 1 would be ill-formed:
yy.cpp:28:42: error: binding reference of type ‘int&’ to ‘const int’ discards qualifiers
using return_type = decltype(View{}(*It{}));
~~~~~~^~~~~~~
Artyer..
5
我在这里做了一个最小的测试用例:https : //godbolt.org/z/QQonMG。
相关详细信息是:
一个using
类型别名并没有实例化一个模板。因此,例如:
template
struct fail_if_true {
static_assert(!b, "template parameter must be false");
};
using fail_if_used = fail_if_true;
不会导致编译时错误(如果fail_if_used
未使用)
ADL还检查模板参数类。在这种情况下,std::vector::iterator
is 模板中__gnu_cxx::__normal_iterator >, Func>
包含一个std::vector
。因此,operator==
将检查在全局命名空间(总是), alp
(由于alp::Iterator
是alp
),__gnu_cxx
和std
。
您View_iterator_base::const_iterator
无效。View_iterator_base::const_interator::result_type
定义为decltype(Func{}(*std::vector::const_iterator{}))
。std::vector::const_iterator{}
将是向量const迭代器,*std::vector::const_iterator{}
也是const int&
。Func::operator()
带有int&
,因此这意味着表达式无效。但是,由于上述原因,如果不使用它不会导致编译时错误。这意味着您的转换运算符为无效类型。
由于您未将其定义为explicit
,如果转换参数不匹配,则将使用转换运算符(转换为无效类型)将其与功能参数进行匹配。显然,这最终将实例化无效类型,因此将引发编译时错误。
我的猜测是iostream
包括string
,它定义std::operator==
了字符串。
这是一个没有std
名称空间的示例:https : //godbolt.org/z/-wlAmv
// Avoid including headers for testing without std::
template struct is_const { static constexpr const bool value = false; } template struct is_const { static constexpr const bool value = true; }
namespace with_another_equals {
struct T {};
bool operator==(const T&, const T&) {
return true;
}
}
namespace ns {
template
struct wrapper {
using invalid_wrapper = wrapper;
operator invalid_wrapper() {}
};
template
bool operator==(const wrapper&, const wrapper&) {
return true;
}
}
template
struct with_invalid {
static_assert(!is_const::value, "Invalid if const");
using invalid = with_invalid;
};
template
void test() {
using wrapped = ns::wrapper>;
wrapped a;
wrapped b;
bool x = operator==(a, b);
bool y = ns::operator==(a, b);
}
template void test();
// Will compile if this line is commented out
template void test();
请注意,仅声明operator const_iterator()
应实例化类型。但这不是因为它在模板中。我的猜测是,在对其进行检查以表明它无法编译(它甚至没有警告-Wall -pedantic
说它在我的示例中没有return语句)之前,已经对其进行了优化(由于未使用,它会在哪里进行编译)。)。
1> Artyer..:
我在这里做了一个最小的测试用例:https : //godbolt.org/z/QQonMG。
相关详细信息是:
一个using
类型别名并没有实例化一个模板。因此,例如:
template
struct fail_if_true {
static_assert(!b, "template parameter must be false");
};
using fail_if_used = fail_if_true;
不会导致编译时错误(如果fail_if_used
未使用)
ADL还检查模板参数类。在这种情况下,std::vector::iterator
is 模板中__gnu_cxx::__normal_iterator >, Func>
包含一个std::vector
。因此,operator==
将检查在全局命名空间(总是), alp
(由于alp::Iterator
是alp
),__gnu_cxx
和std
。
您View_iterator_base::const_iterator
无效。View_iterator_base::const_interator::result_type
定义为decltype(Func{}(*std::vector::const_iterator{}))
。std::vector::const_iterator{}
将是向量const迭代器,*std::vector::const_iterator{}
也是const int&
。Func::operator()
带有int&
,因此这意味着表达式无效。但是,由于上述原因,如果不使用它不会导致编译时错误。这意味着您的转换运算符为无效类型。
由于您未将其定义为explicit
,如果转换参数不匹配,则将使用转换运算符(转换为无效类型)将其与功能参数进行匹配。显然,这最终将实例化无效类型,因此将引发编译时错误。
我的猜测是iostream
包括string
,它定义std::operator==
了字符串。
这是一个没有std
名称空间的示例:https : //godbolt.org/z/-wlAmv
// Avoid including headers for testing without std::
template struct is_const { static constexpr const bool value = false; } template struct is_const { static constexpr const bool value = true; }
namespace with_another_equals {
struct T {};
bool operator==(const T&, const T&) {
return true;
}
}
namespace ns {
template
struct wrapper {
using invalid_wrapper = wrapper;
operator invalid_wrapper() {}
};
template
bool operator==(const wrapper&, const wrapper&) {
return true;
}
}
template
struct with_invalid {
static_assert(!is_const::value, "Invalid if const");
using invalid = with_invalid;
};
template
void test() {
using wrapped = ns::wrapper>;
wrapped a;
wrapped b;
bool x = operator==(a, b);
bool y = ns::operator==(a, b);
}
template void test();
// Will compile if this line is commented out
template void test();
请注意,仅声明operator const_iterator()
应实例化类型。但这不是因为它在模板中。我的猜测是,在对其进行检查以表明它无法编译(它甚至没有警告-Wall -pedantic
说它在我的示例中没有return语句)之前,已经对其进行了优化(由于未使用,它会在哪里进行编译)。)。