qzh*_*ong 4 c++ name-lookup template-aliases clang++
以下代码可以使用 MSVC(v19.38) 编译,但使用 GCC(13.2) 和 Clang(17.0.1) 编译失败。但旧版本的 GCC,例如 11.2,可以正常工作。
#include <type_traits>
#ifdef MY_INT
template<typename T, T V> struct my_int
{
static constexpr T value = V;
using value_type = T;
constexpr operator value_type() const noexcept { return value; }
constexpr value_type operator()() const noexcept { return value; }
};
template<auto V> using constant_int_t = my_int<decltype(V), V>;
#else
template<auto V> using constant_int_t = std::integral_constant<decltype(V), V>;
#endif
template<typename T1, typename T2>
using add_t = decltype(T1{} + T2{});
template<typename T1, typename T2>
constexpr auto operator+(T1, T2)
{
return constant_int_t<T1::value + T2::value>{};
}
using v1 = constant_int_t<1>;
using v2 = constant_int_t<2>;
using v3 = add_t<v1, v2>;
static_assert(std::is_same_v<v3, constant_int_t<3>>);
Run Code Online (Sandbox Code Playgroud)
Clang 抱怨v3is 类型为 int,这可能是因为它无法识别operator+在 termplate 别名后定义的内容add_t,并在处理添加时执行了隐式类型转换。
如果我使用我自己的常量 int 类型(my_int<T,V>与 几乎相同std::integral_constant<T,V>),clang 将编译它。add_t如果我交换和的定义顺序operator+,它也可以正常工作。
那么,这是 Clang 和 GCC 的 bug 吗?还是一种未明确的行为?
当您使用 时my_int,::(全局)命名空间是关联的命名空间(因为my_int是在::命名空间中定义的),因此auto ::operator+(T1, T2);可以通过 ADL 找到。
如果使用std::integral_constant<int, x>,则唯一关联的命名空间是std. 因此,operator+在 ADL 的命名空间中查找std::,没有找到任何适用的内容(因此int operator+(int, int)在转换参数后使用内置函数)
如果您operator+之前移动了定义add_t,则可以通过普通/非 ADL 查找找到它。