Clé*_*ent 10 c++ implicit-conversion template-meta-programming c++14 c++20
TL;DR:我正在寻找与以下 C++20 MWE 等效的 C++14:
template<int sz>
struct bits {
int v; // note explicit(expr) below
explicit(sz > 1) operator bool() const { return bool(v); }
};
int main() {
bool c = bits<1>{1}; // Should work
bool d = bits<3>{1}; // Should fail
}
Run Code Online (Sandbox Code Playgroud)
语境:
bits<sz>我们有一个表示长度为位向量的C++ 类sz。过去,对 all 的转换bool是隐式的sz,但事实证明这很容易出错,因此我们改为operator bool()显式转换。
然而,1-bit位向量(在我们的上下文中)几乎完全等同于布尔值,因此当 时最好是operator bool()隐式的sz == 1。
explicit(sz > 1)这可以在C++20中实现,但我们的目标是 C++14。
我尝试重载 for 运算符sz == 1,但似乎explicit限定符也适用于它:以下内容不起作用。
template<int sz>
struct bits {
int v;
explicit operator bool() const { return bool(v); }
};
template<> bits<1>::operator bool() const {
return bool(v);
}
int main() {
bool c = bits<1>{1}; // Fails: "No viable conversion"
}
Run Code Online (Sandbox Code Playgroud)
因此问题是:我如何在 C++14 中指定operator bool()应该仅显式地用于sz > 1?
我在下面为好奇的读者提供了一些背景知识。
背景:
这个问题是在 C++ 中嵌入式领域特定语言的上下文中出现的。业务要求之一是operator==返回 abit<1>而不是 a bool。这与 GNU 的 libstdc++ 配合顺利,但我们在 macOS 上遇到了这一要求的麻烦,因为 libstdc++ 实现了operator==使用带有谓词std::array的版本,并使用返回body的结构(在我们的例子中)实现了该谓词返回 a ,导致转换错误)。std::equaloperator()boola == bbits<1>
为了让好奇的读者具体了解,以下程序在 GNU 上编译得很好,但在 macOS 上却不行,因为operator==onstd::array的实现方式:
#include <array>
struct S { explicit operator bool() const { return true; } };
struct T {};
S operator==(T, T) { return S(); }
int main() {
std::array<T, 1> arr = { T() };
return arr == arr;
}
Run Code Online (Sandbox Code Playgroud)
这是因为在 on 数组的实现深处,==GNU libstdc++ 有一个 test if (!(*it1 == *it2)),它可以毫无问题地调用explicit operator bool()on ,而在 macOS 上,库使用的with大致相当于,它不会进行类型检查。
Sif (!__pred(*it1, *it2))__predbool __pred(S a, S b) { return a == b; }
bol*_*lov 13
是的。您可以使用 SFINAE 转换运算符:
#include <type_traits>
template<int sz>
struct bits {
int v;
explicit operator bool() const { return bool(v); }
template <int S = sz>
operator std::enable_if_t<S == 1, bool> () const { return bool(v);}
};
Run Code Online (Sandbox Code Playgroud)
在 Godbolt 上检查一下
int main()
{
bool c1 = bits<1>{1}; // Ok
bool c2 = bits<3>{1}; // error cannot convert
bool c3 = static_cast<bool>(bits<3>{1}); // OK
}
Run Code Online (Sandbox Code Playgroud)