提问人:Vladislavs Burakovs 提问时间:9/30/2023 更新时间:9/30/2023 访问量:59
使用不同编译器的函数模板实例化的不同行为
Different behavior of function template instantiation using different compilers
问:
描述
这是一段代码,clang、gcc 和 msvc 编译器对其进行了不同的处理:
#include <type_traits>
template <bool> struct enum_as_byte_check;
template <> struct
[[deprecated("deprecated warning")]] enum_as_byte_check<true> {};
template <class T>
using is_scoped_enum = std::integral_constant<bool, !std::is_convertible<T,int>{}
&& std::is_enum<T>{}>;
template<class EnumT>
class enum_as_byte
{
typedef enum_as_byte_check<is_scoped_enum<EnumT>::value> Check;
};
template<typename EnumT>
static inline void bar(const EnumT)
{
}
template<typename EnumT>
static inline void bar(enum_as_byte<EnumT>)
{
static_assert(false && "");
}
enum class Foo : int { };
enum Bar {};
static_assert(is_scoped_enum<Foo>::value);
static_assert(!is_scoped_enum<Bar>::value);
int main()
{
bar<Foo>(Foo{});
}
结果(指向相应 Compiler Explorer 设置的链接):
-
<source>:13:10: warning: 'enum_as_byte_check<true>' is deprecated: deprecated warning [-Wdeprecated-declarations] 13 | typedef enum_as_byte_check<is_scoped_enum<EnumT>::value> Check; | ^ <source>:35:14: note: in instantiation of template class 'enum_as_byte<Foo>' requested here 35 | bar<Foo>(Foo{}); | ^ <source>:35:5: note: while substituting deduced template arguments into function template 'bar' [with EnumT = Foo] 35 | bar<Foo>(Foo{}); | ^ <source>:5:3: note: 'enum_as_byte_check<true>' has been explicitly marked deprecated here 5 | [[deprecated("deprecated warning")]] enum_as_byte_check<true> {}; | ^
1.1. 如果被注释:无警告
bar<Foo>(Foo{});
-
<source>:25:5: error: static assertion failed due to requirement 'false && ""' static_assert(false && ""); ^ ~~~~~~~~~~~ <source>:13:10: warning: 'enum_as_byte_check<true>' is deprecated: deprecated warning [-Wdeprecated-declarations] typedef enum_as_byte_check<is_scoped_enum<EnumT>::value> Check; ^ <source>:35:14: note: in instantiation of template class 'enum_as_byte<Foo>' requested here bar<Foo>(Foo{}); ^ <source>:35:5: note: while substituting deduced template arguments into function template 'bar' [with EnumT = Foo] bar<Foo>(Foo{}); ^ <source>:5:3: note: 'enum_as_byte_check<true>' has been explicitly marked deprecated here [[deprecated("deprecated warning")]] enum_as_byte_check<true> {}; ^
2.1. 如果
static_assert
被注释:<source>:13:10: warning: 'enum_as_byte_check<true>' is deprecated: deprecated warning [-Wdeprecated-declarations] typedef enum_as_byte_check<is_scoped_enum<EnumT>::value> Check; ^ <source>:35:14: note: in instantiation of template class 'enum_as_byte<Foo>' requested here bar<Foo>(Foo{}); ^ <source>:35:5: note: while substituting deduced template arguments into function template 'bar' [with EnumT = Foo] bar<Foo>(Foo{}); ^ <source>:5:3: note: 'enum_as_byte_check<true>' has been explicitly marked deprecated here [[deprecated("deprecated warning")]] enum_as_byte_check<true> {}; ^
2.2. 如果被评论而static_assert不是:
bar<Foo>(Foo{});
<source>:25:5: error: static assertion failed due to requirement 'false && ""' static_assert(false && ""); ^ ~~~~~~~~~~~
2.3 如果两者都被注释:: 无警告
bar<Foo>(Foo{});
static_assert
x86-64 GCC 12.3 版本:
<source>: In function 'void bar(enum_as_byte<EnumT>)': <source>:25:25: error: static assertion failed 25 | static_assert(false && ""); | ~~~~~~^~~~~
4.1. 相同的输出 if 被注释
bar<Foo>(Foo{}());
4.2. 如果被评论,则不发出警告
static_assert
问题:
- 的定义中是否算作用户定义的转换?
enum_as_byte<EnumT>
bar
- 从标准的角度来看,什么编译器(或编译器版本)是正确的?
- 标准中指定正确行为的段落是什么?
答:
在那个测试用例中,你有太多的事情要做。举个最小的例子!
问题是P2593(C++23),有些编译器版本已经支持,有些则不支持。我们可以忽略这一点。static_assert(false)
您的真正问题似乎是关于何时将其应用于特定专业化而不是主模板的预期行为。每个人都同意,对于使用该特定专业化,应发出弃用警告。[[deprecated]]
GCC 似乎只对不依赖于任何模板参数 (Godbolt:)的已弃用专用化的使用发出弃用警告
template<class> struct A;
template<> struct [[deprecated]] A<int> {};
template<class T>
void a() { A<T> t; } // Clang warns (in phase 2), GCC never does
template<class T>
void b() { A<int> t; } // Both warn (in phase 1)
void c() { A<int> t; } // Both warn
template void a<int>();
template void b<float>();
是“真正使用”还是仅用作别名根本不重要; 仍然被警告,即使在那之后从未使用过。(神螺栓。A<int>
using U = A<int>
U
)
最后,你问:
的定义中是否算作用户定义的转换?
enum_as_byte<EnumT>
bar
不,“[用户定义的]转化”是在评估过程中发生的;它不是语法属性。由于重载解析从不选择,因此不会发生对它的调用,因此不会将任何内容转换为 。bar(enum_as_byte<EnumT>)
enum_as_byte<EnumT>
评论