[英]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 在 struct 命名空間中找不到正確的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);
}
這編譯,但不鏈接:編輯。 我相信它沒有鏈接,因為模板沒有實例化,因此在鏈接時失敗(類似於上面的幼稚實現)。
結論
即使我以某種方式找到了實現我想要的方法,但如果我不想在 class 定義中定義運算符怎么辦。
提前致謝。
這編譯,但不鏈接!
編譯但不鏈接,因為您聲明了一個非模板運算符(它在模板結構內但不是模板函數)
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);
}
並且模板定義不能匹配非模板聲明。
您可以嘗試將 function 聲明為模板之一
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;
不被稱為模板 function 因為模板參數T
無法推斷,因為它在未推斷的上下文中(在最后一個::
之前),正如 Benny K 在評論中指出的那樣。
因此,模板operator~()
將dummy<double>::a
轉換為int
並應用int
的~
運算符(類型為 result int
)。
您可以通過顯式調用 function operator~()
auto a = operator~(dummy<double>::a);
你應該得到一個“沒有匹配的 function 調用'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>
類型定義不同的運算符。
恕我直言,最簡單、安全和優雅的解決方案是您的工作解決方案:在結構內聲明/定義運算符。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.