使用以下模板來嘗試使C++ 11/14的新類類枚舉按需工作,我發現下面的代碼甚至不會嘗試調用隱式ctor以使用將適合通過VS2013更新1非成員模板:爲什麼不是我的隱式ctor在下面調用
BitTest
定義爲:
template <typename enumT>
bool BitTest(const EnumeratedFlags<enumT>& lhs, const EnumeratedFlags<enumT>& rhs)
{
return (lhs & rhs);
}
測試代碼與異常:
enum class Flags { None = 0x00, CanChangeDataSources = 0x01, RequiresExclusiveAccess = 0x02 };
EnumeratedFlags<Flags> lhs(Flags::CanChangeDataSources);
// ... the following fails to even attempt to convert the Foo::Flags
if (BitTest(lhs, Flags::CanChangeDataSources)) { DoSomething(); }
// this compiles, but I don't know why it's necessary (and this is annoying and ugly)...
if (BitTest(lhs, EnumeratedFlags<Flags>(Flags::CanChangeDataSources))) { DoSomething(); }
這裏是模板defini重刑我目前嘗試使用:
template <typename enumT>
class EnumeratedFlags
{
public:
typedef enumT enum_type;
typedef typename std::underlying_type<enumT>::type store_type;
// constructors
EnumeratedFlags()
: m_bits(0)
{
}
EnumeratedFlags(enum_type flag)
: m_bits(static_cast<store_type>(flag))
{
}
explicit EnumeratedFlags(store_type value)
: m_bits(value)
{
}
EnumeratedFlags(const std::initializer_list<enum_type> & initializers)
: m_bits(0)
{
for (auto flag : initializers)
m_bits |= static_cast<store_type>(flag);
}
// operators
operator std::string() const
{
return to_string();
}
bool operator [] (enum_type flag) const
{
return test(flag);
}
store_type operator *() const
{
return m_bits;
}
operator bool() const
{
return m_bits != store_type(0);
}
// explicit accessors
store_type bits() const
{
return m_bits;
}
std::string to_string() const
{
std::string str(size(), '0');
for (size_t x = 0; x < size(); ++x)
str[size() - x - 1] = (m_bits & (1 << x) ? '1' : '0');
return str;
}
EnumeratedFlags & set(enum_type flag)
{
BitSet(m_bits, static_cast<store_type>(flag));
return *this;
}
EnumeratedFlags & set_if(enum_type flag, bool set_or_clear)
{
BitSetIf(m_bits, static_cast<store_type>(flag), set_or_clear);
return *this;
}
EnumeratedFlags & clear()
{
m_bits = store_type(0);
return *this;
}
EnumeratedFlags & flip()
{
m_bits = ~m_bits;
return *this;
}
EnumeratedFlags & flip(enum_type flag)
{
m_bits ^= static_cast<store_type>(flag);
return *this;
}
size_t count() const
{
// http://www-graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
store_type bits = m_bits;
size_t total = 0;
for (; bits != 0; ++total)
{
bits &= bits - 1; // clear the least significant bit set
}
return total;
}
size_t size() const
{
// one character per possible bit
return sizeof(enum_type) * 8;
}
bool test(enum_type flag) const
{
return BitTest(m_bits, static_cast<store_type>(flag));
}
bool any() const
{
return m_bits != 0;
}
bool none() const
{
return m_bits == 0;
}
private:
store_type m_bits;
};
template <class charT, class traits, typename enumT>
std::basic_ostream<charT, traits> & operator << (std::basic_ostream<charT, traits> & os, const EnumeratedFlags<enumT> & flags)
{
return os << flags.to_string();
}
template <typename enumT>
EnumeratedFlags<enumT> operator & (const EnumeratedFlags<enumT>& lhs, const EnumeratedFlags<enumT>& rhs)
{
return EnumeratedFlags<enumT>(lhs.bits() & rhs.bits());
}
template <typename enumT>
EnumeratedFlags<enumT> operator | (const EnumeratedFlags<enumT>& lhs, const EnumeratedFlags<enumT>& rhs)
{
return EnumeratedFlags<enumT>(lhs.bits() | rhs.bits());
}
template <typename enumT>
EnumeratedFlags<enumT> operator^(const EnumeratedFlags<enumT>& lhs, const EnumeratedFlags<enumT>& rhs)
{
return EnumeratedFlags<enumT>(lhs.bits()^rhs.bits());
}
template <typename enumT>
bool BitTest(const EnumeratedFlags<enumT>& lhs, const EnumeratedFlags<enumT>& rhs)
{
return (lhs & rhs);
}
基本上,我本來以爲在X (const T & lhs, const T & rhs)
形式的任何自由函數將最多使用一個用戶自定義轉換找到BitTest<>()
有效的調用,上面。相反,我必須在上面的代碼中明確地聲明轉換,以使編譯器使用此函數,這大大降低了template class EnumeratedFlags<>
的表達能力。一般來說,C++迫使我堅持認爲,沒有一種好的方法來使用位,它結合了使用範圍枚舉(enum class Foo
)和位域(或類似命名集合)的所有功能和良好的編程習慣),並且在保持編譯器基本的完整性檢查(不會自動轉換爲數字類型或反之)的同時,使客戶端程序員非常容易地使用它們。似乎需要在語言規範中進行更全面的改進,才能實現真正照亮的位域枚舉......或者我錯過了什麼?
當模板類型扣參與,沒有用戶定義的轉換被考慮。 – dyp
相關:http://stackoverflow.com/q/18553843/420683 – dyp
你在BitTest中要求一個'EnumeratedFlags'類型,但是你不會在第一個if中爲'rhs'參數傳遞'EnumeratedFlags'類型聲明。不知道'enum'應該如何隱式轉換爲'EnumeratedFlags'。 – Brian