是否有 C++14 替代 C++20 中引入的显式(expr)?

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)