为什么我可以覆盖 -(否定)和! (不是)但不是~(按位不是)?
Why can I override the operators for - (negation) and ! (not) but not ~ (bitwise not)?
为什么下面定义了!
和-
运算符,而没有定义~
运算符?
#include <type_traits>
#include <cstdint>
#include <typeinfo>
#include <cstdio>
template <typename T, T v>
struct integral_constant
: std::integral_constant<T, v>
{
};
#define DECL_UNARY_OP(op) \
template <typename T, T t> \
constexpr integral_constant<decltype(op t), (op t)> \
operator op(integral_constant<T, t>) \
{ return {}; } \
DECL_UNARY_OP(~);
DECL_UNARY_OP(-);
DECL_UNARY_OP(!);
int main() {
constexpr auto x = integral_constant<uint8_t, 1>{};
constexpr auto y = integral_constant<uint8_t, 10>{};
constexpr auto z = integral_constant<uint8_t, 100>{};
puts(typeid(-x).name()); // integral_constant<...>
puts(typeid(~y).name()); // int!
puts(typeid(!z).name()); // integral_constant<...>
}
在 GCC-4.8.2 上编译它得到 the following on godbolt,您可以清楚地看到中间操作已经从 integral_constant
类型衰减。
为什么会这样?
通过消除std::integral_constant
可以获得更简单的再现:
#include <cstdint>
#include <typeinfo>
#include <cstdio>
template <typename T, T v>
struct integral_constant { };
template <typename T, T t>
constexpr integral_constant<decltype(~t), (~t)>
operator ~(integral_constant<T, t>) { return {}; }
int main() {
constexpr auto y = integral_constant<uint8_t, 10>{};
puts(typeid(~y).name());
}
<source>: In function 'int main()':
<source>:17:17: error: no match for 'operator~' (operand type is 'const integral_constant<unsigned char, 10u>')
puts(typeid(~y).name());
^
<source>:17:17: note: candidate is:
<source>:11:1: note: template<class T, T t> constexpr integral_constant<decltype (~ t), (~ t)> operator~(integral_constant<T, t>)
operator ~(integral_constant<T, t>)
^
<source>:11:1: note: template argument deduction/substitution failed:
<source>: In substitution of 'template<class T, T t> constexpr integral_constant<decltype (~ t), (~ t)> operator~(integral_constant<T, t>) [with T = unsigned char; T t = 10u]':
<source>:17:18: required from here
<source>:11:1: error: 't' was not declared in this scope
Compiler returned: 1
看来这可以通过添加额外的括号来解决,
-integral_constant<decltype(~t), (~t)>
+integral_constant<decltype((~t)), (~t)>
为什么下面定义了!
和-
运算符,而没有定义~
运算符?
#include <type_traits>
#include <cstdint>
#include <typeinfo>
#include <cstdio>
template <typename T, T v>
struct integral_constant
: std::integral_constant<T, v>
{
};
#define DECL_UNARY_OP(op) \
template <typename T, T t> \
constexpr integral_constant<decltype(op t), (op t)> \
operator op(integral_constant<T, t>) \
{ return {}; } \
DECL_UNARY_OP(~);
DECL_UNARY_OP(-);
DECL_UNARY_OP(!);
int main() {
constexpr auto x = integral_constant<uint8_t, 1>{};
constexpr auto y = integral_constant<uint8_t, 10>{};
constexpr auto z = integral_constant<uint8_t, 100>{};
puts(typeid(-x).name()); // integral_constant<...>
puts(typeid(~y).name()); // int!
puts(typeid(!z).name()); // integral_constant<...>
}
在 GCC-4.8.2 上编译它得到 the following on godbolt,您可以清楚地看到中间操作已经从 integral_constant
类型衰减。
为什么会这样?
通过消除std::integral_constant
可以获得更简单的再现:
#include <cstdint>
#include <typeinfo>
#include <cstdio>
template <typename T, T v>
struct integral_constant { };
template <typename T, T t>
constexpr integral_constant<decltype(~t), (~t)>
operator ~(integral_constant<T, t>) { return {}; }
int main() {
constexpr auto y = integral_constant<uint8_t, 10>{};
puts(typeid(~y).name());
}
<source>: In function 'int main()':
<source>:17:17: error: no match for 'operator~' (operand type is 'const integral_constant<unsigned char, 10u>')
puts(typeid(~y).name());
^
<source>:17:17: note: candidate is:
<source>:11:1: note: template<class T, T t> constexpr integral_constant<decltype (~ t), (~ t)> operator~(integral_constant<T, t>)
operator ~(integral_constant<T, t>)
^
<source>:11:1: note: template argument deduction/substitution failed:
<source>: In substitution of 'template<class T, T t> constexpr integral_constant<decltype (~ t), (~ t)> operator~(integral_constant<T, t>) [with T = unsigned char; T t = 10u]':
<source>:17:18: required from here
<source>:11:1: error: 't' was not declared in this scope
Compiler returned: 1
看来这可以通过添加额外的括号来解决,
-integral_constant<decltype(~t), (~t)>
+integral_constant<decltype((~t)), (~t)>