运算符重载嵌套在 class 中的枚举
Operator overloading on an enum nested in a class
问题
给定以下代码:
template <typename T>
struct dummy {
enum enumenum { a = 1, b = 2, c = 4 };
};
int main() {
// I want this line to expands as :
// dummy<double>::enumenum a = operator~(dummy<double>::a);
auto a = ~dummy<double>::a;
}
如何在 enumenum
上重载运算符?
我正在使用标准 C++14。
我试过的
天真的实现:
template <typename T>
typename dummy<T>::enumenum
operator~(typename dummy<T>::enumenum a) {
return static_cast<typename dummy<T>::enumenum>(operator~(a));
}
不幸的是,有问题的行扩展为:
int a = ~static_cast<int>(dummy<double>::a);
这意味着未使用运算符(这是默认行为)。
是因为 ADL 无法在结构命名空间中找到正确的 operator~()
(这甚至是一回事吗?)?
然后我尝试了:(注意friend
)
template <typename T>
struct dummy {
enum enumenum { a, b, c };
friend enumenum operator~(enumenum a) {
return static_cast<enumenum>(~a);
}
};
这实际上可以工作并扩展为:
template <>
struct dummy<double> {
enum enumenum {
a = static_cast<unsigned int>(1),
b = static_cast<unsigned int>(2),
c = static_cast<unsigned int>(4)
};
friend inline dummy<double>::enumenum operator~(dummy<double>::enumenum a) {
return static_cast<dummy<double>::enumenum>(operator~(a));
}
};
int main()
{
dummy<double>::enumenum a = operator~(dummy<double>::a);
}
这就是我想要的行为。除了,如果我不想在 class 主体中定义运算符怎么办。
所以我尝试了:
template <typename T>
struct dummy {
enum enumenum { a = 1, b = 2, c = 4 };
// if inline : inline function 'operator~' is not defined [-Wundefined-inline]
// and adding inline to the template below does not help
friend enumenum operator~(enumenum a);
};
template <typename T>
typename dummy<T>::enumenum
operator~(typename dummy<T>::enumenum a) {
return static_cast<typename dummy<T>::enumenum>(~a);
}
int main() {
auto a = ~dummy<double>::a;
}
上面的代码展开为:
template<>
struct dummy<double>
{
enum enumenum
{
a = static_cast<unsigned int>(1),
b = static_cast<unsigned int>(2),
c = static_cast<unsigned int>(4)
};
friend dummy<double>::enumenum operator~(dummy<double>::enumenum a);
};
int main()
{
dummy<double>::enumenum a = operator~(dummy<double>::a);
}
这会编译,但 不会 link!
编辑:我相信它不会 link 因为模板没有实例化因此在 link 时失败(类似于上面的天真实现)。
结论
即使我以某种方式找到了实现我想要的方法,如果我不想在 class 定义中定义运算符怎么办。
提前致谢。
This compiles, but does not link!
编译但不编译 link 因为您声明了一个非模板运算符(它在模板结构中但不是模板函数)
friend enumenum operator~(enumenum a);
然后你定义一个模板一个
template <typename T>
typename dummy<T>::enumenum
operator~(typename dummy<T>::enumenum a) {
return static_cast<typename dummy<T>::enumenum>(~a);
}
并且模板定义无法匹配非模板声明。
您可以尝试将函数声明为模板一个
template <typename T>
struct dummy
{
enum enumenum { a = 1, b = 2, c = 4 };
template <typename U>
friend typename dummy<U>::enumenum
operator~ (typename dummy<U>::enumenum const & a);
};
template <typename T>
typename dummy<T>::enumenum
operator~ (typename dummy<T>::enumenum const & a)
{ return static_cast<typename dummy<T>::enumenum>(~a); }
int main ()
{
auto a = ~dummy<double>::a;
}
但是,不幸的是,这个编译但是,调用 ~
运算符如下
~dummy<double>::a;
没有被称为模板函数,因为无法推导模板参数 T
因为它处于非推导上下文中(在最后一个 ::
之前),正如 Benny K 所指出的在评论中。
因此,代替模板 operator~()
,将 dummy<double>::a
转换为 int
并应用 int
的 ~
运算符(结果类型为int
).
您可以通过显式调用函数验证这一点operator~()
auto a = operator~(dummy<double>::a);
你应该得到一个“没有匹配的函数调用 'operator~'”错误(注释“注意:候选模板被忽略:无法推断模板参数 'T'”)或类似的东西。
要使此解决方案有效,您必须说明 class 的类型,以避免模板推导
auto a = operator~<double>(dummy<double>::a);
现在,您可以验证 a
是 dummy<double>::enumenum
static_assert( std::is_same<decltype(a), dummy<double>::enumenum>::value, "!" );
但是,显然,这不是一个令人满意的解决方案(而且非常危险,如果您忘记避免简单地使用 ~
)。
否则您可以将运算符定义为非模板
template <typename T>
struct dummy
{
enum enumenum { a = 1, b = 2, c = 4 };
friend enumenum operator~ (enumenum const & a);
};
dummy<double>::enumenum
operator~(dummy<double>::enumenum const & a)
{ return static_cast<dummy<double>::enumenum>(~a); }
int main ()
{
auto a = ~dummy<double>::a;
}
但是您必须为每种 dummy<T>
类型定义不同的运算符。
恕我直言,最简单、安全和优雅的解决方案是您的工作方案:declare/define 结构中的运算符。
问题
给定以下代码:
template <typename T>
struct dummy {
enum enumenum { a = 1, b = 2, c = 4 };
};
int main() {
// I want this line to expands as :
// dummy<double>::enumenum a = operator~(dummy<double>::a);
auto a = ~dummy<double>::a;
}
如何在 enumenum
上重载运算符?
我正在使用标准 C++14。
我试过的
天真的实现:
template <typename T>
typename dummy<T>::enumenum
operator~(typename dummy<T>::enumenum a) {
return static_cast<typename dummy<T>::enumenum>(operator~(a));
}
不幸的是,有问题的行扩展为:
int a = ~static_cast<int>(dummy<double>::a);
这意味着未使用运算符(这是默认行为)。
是因为 ADL 无法在结构命名空间中找到正确的 operator~()
(这甚至是一回事吗?)?
然后我尝试了:(注意friend
)
template <typename T>
struct dummy {
enum enumenum { a, b, c };
friend enumenum operator~(enumenum a) {
return static_cast<enumenum>(~a);
}
};
这实际上可以工作并扩展为:
template <>
struct dummy<double> {
enum enumenum {
a = static_cast<unsigned int>(1),
b = static_cast<unsigned int>(2),
c = static_cast<unsigned int>(4)
};
friend inline dummy<double>::enumenum operator~(dummy<double>::enumenum a) {
return static_cast<dummy<double>::enumenum>(operator~(a));
}
};
int main()
{
dummy<double>::enumenum a = operator~(dummy<double>::a);
}
这就是我想要的行为。除了,如果我不想在 class 主体中定义运算符怎么办。
所以我尝试了:
template <typename T>
struct dummy {
enum enumenum { a = 1, b = 2, c = 4 };
// if inline : inline function 'operator~' is not defined [-Wundefined-inline]
// and adding inline to the template below does not help
friend enumenum operator~(enumenum a);
};
template <typename T>
typename dummy<T>::enumenum
operator~(typename dummy<T>::enumenum a) {
return static_cast<typename dummy<T>::enumenum>(~a);
}
int main() {
auto a = ~dummy<double>::a;
}
上面的代码展开为:
template<>
struct dummy<double>
{
enum enumenum
{
a = static_cast<unsigned int>(1),
b = static_cast<unsigned int>(2),
c = static_cast<unsigned int>(4)
};
friend dummy<double>::enumenum operator~(dummy<double>::enumenum a);
};
int main()
{
dummy<double>::enumenum a = operator~(dummy<double>::a);
}
这会编译,但 不会 link! 编辑:我相信它不会 link 因为模板没有实例化因此在 link 时失败(类似于上面的天真实现)。
结论
即使我以某种方式找到了实现我想要的方法,如果我不想在 class 定义中定义运算符怎么办。
提前致谢。
This compiles, but does not link!
编译但不编译 link 因为您声明了一个非模板运算符(它在模板结构中但不是模板函数)
friend enumenum operator~(enumenum a);
然后你定义一个模板一个
template <typename T>
typename dummy<T>::enumenum
operator~(typename dummy<T>::enumenum a) {
return static_cast<typename dummy<T>::enumenum>(~a);
}
并且模板定义无法匹配非模板声明。
您可以尝试将函数声明为模板一个
template <typename T>
struct dummy
{
enum enumenum { a = 1, b = 2, c = 4 };
template <typename U>
friend typename dummy<U>::enumenum
operator~ (typename dummy<U>::enumenum const & a);
};
template <typename T>
typename dummy<T>::enumenum
operator~ (typename dummy<T>::enumenum const & a)
{ return static_cast<typename dummy<T>::enumenum>(~a); }
int main ()
{
auto a = ~dummy<double>::a;
}
但是,不幸的是,这个编译但是,调用 ~
运算符如下
~dummy<double>::a;
没有被称为模板函数,因为无法推导模板参数 T
因为它处于非推导上下文中(在最后一个 ::
之前),正如 Benny K 所指出的在评论中。
因此,代替模板 operator~()
,将 dummy<double>::a
转换为 int
并应用 int
的 ~
运算符(结果类型为int
).
您可以通过显式调用函数验证这一点operator~()
auto a = operator~(dummy<double>::a);
你应该得到一个“没有匹配的函数调用 'operator~'”错误(注释“注意:候选模板被忽略:无法推断模板参数 'T'”)或类似的东西。
要使此解决方案有效,您必须说明 class 的类型,以避免模板推导
auto a = operator~<double>(dummy<double>::a);
现在,您可以验证 a
是 dummy<double>::enumenum
static_assert( std::is_same<decltype(a), dummy<double>::enumenum>::value, "!" );
但是,显然,这不是一个令人满意的解决方案(而且非常危险,如果您忘记避免简单地使用 ~
)。
否则您可以将运算符定义为非模板
template <typename T>
struct dummy
{
enum enumenum { a = 1, b = 2, c = 4 };
friend enumenum operator~ (enumenum const & a);
};
dummy<double>::enumenum
operator~(dummy<double>::enumenum const & a)
{ return static_cast<dummy<double>::enumenum>(~a); }
int main ()
{
auto a = ~dummy<double>::a;
}
但是您必须为每种 dummy<T>
类型定义不同的运算符。
恕我直言,最简单、安全和优雅的解决方案是您的工作方案:declare/define 结构中的运算符。