关于模板别名和用户定义运算符的顺序的奇怪行为

问题描述 投票:0回答:1

下面这段代码可以使用GCC或MSVC编译,但使用Clang编译失败

#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>>);

Clang 抱怨

v3
是 int 类型,这可能是因为它未能发现在 termplate 别名
operator+
之后定义的
add_t
,并在处理添加时执行了隐式类型转换。

如果我使用自己的常量 int 类型(

my_int<T,V>
,与
std::integral_constant<T,V>
几乎相同),clang 会编译它。如果我交换
add_t
operator+
的定义顺序,它也可以正常工作。

那么,这是 clang 的 bug 吗?还是未指定的行为?

c++ clang++ template-aliases
1个回答
3
投票

我认为这是 Clang 的一个错误。

[临时别名]/2:

当 template-id 引用别名模板的特化时,它相当于用其 template-argument 替换别名模板的定义类型 id 中的模板参数而获得的关联类型。

所以

using v3 = add_t<v1, v2>;

应等于

using v3 = decltype(v1{} + v2{});

但 Clang 将它们视为不同类型。

© www.soinside.com 2019 - 2024. All rights reserved.