变体中从原始类型到用户定义类型的隐式转换

问题描述 投票:0回答:1

我有两个类

Int
Bool
模仿各自的原始类型,应该在
std::variant
中使用。几乎可以编译的例子:

#include <iostream>
#include <string>
#include <variant>
using namespace std;


class Bool {
 public:
  Bool(bool val) : m_value(val) {}

  operator bool() const { return m_value; }

 private:
  bool m_value{false};
};

class Int {
 public:
  Int(int val) : m_value(val) {}

  operator int() const { return m_value; }

 private:
  int m_value{0};
};


int main() {
  using VariantT = std::variant<std::string, Bool, Int>;
  Bool b1 = true;
  VariantT v1 = b1;    // (1) works
  VariantT v2 = true;  // (2) does not work
  VariantT v3 = 1;     // (3) does not work
  return 0;
}

如果我从 VariantT 中删除

Bool
,则 (3) 有效。删除
Int
使 (1) 和 (2) 起作用。

但是当

Int
Bool
存在时,没有任何作用:

test.cpp:32:12: error: no viable conversion from 'bool' to 'VariantT' (aka 'variant<basic_string<char>, Bool, Int>')
  VariantT v2 = true;  // (2) does not work
           ^    ~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/variant:1365:7: note: candidate constructor not viable: no known conversion from 'bool' to 'const variant<basic_string<char>, Bool, Int> &' for 1st argument
      variant(const variant& __rhs) = default;
      ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/variant:1366:7: note: candidate constructor not viable: no known conversion from 'bool' to 'variant<basic_string<char>, Bool, Int> &&' for 1st argument
      variant(variant&&) = default;
      ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/variant:1378:2: note: candidate template ignored: requirement '18446744073709551615UL < sizeof...(_Types)' was not satisfied [with _Tp = bool, $1 = enable_if_t<sizeof...(_Types) != 0>, $2 = enable_if_t<__not_in_place_tag<bool>>]
        variant(_Tp&& __t)
        ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/variant:1388:2: note: explicit constructor is not a candidate
        variant(in_place_type_t<_Tp>, _Args&&... __args)
        ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/variant:1408:2: note: explicit constructor is not a candidate
        variant(in_place_index_t<_Np>, _Args&&... __args)

(使用 clang++ 16 和 c++17)

我希望能够将原始类型分配给

VariantT
并将它们隐式转换为
Int
Bool

为什么不起作用?我怎样才能让它发挥作用?

谢谢!

c++ c++17 std variant
1个回答
0
投票

在 C++ 中,例如,如果函数参数是

int
,则可以传入
bool
值,并且会发生隐式转换。反之亦然。这会导致一个问题:

VariantT v2 = true;  // (2) does not work

这里有两种可能的、不同的隐式转换。

  1. 使用带有

    Bool
    参数的
    true
    构造函数来构造
    Bool
    ,然后使用您的
    Bool
    构造变体。

  2. 使用

    Int
    的构造函数,将转换为int值1的
    true
    传递给构造函数,构造一个
    Int
    ,然后用
    Int
    构造变体。

这两种转换都不优于另一种,因此重载解析因此失败。

我怎样才能让它发挥作用?

改变一些东西。重新设计一些东西,做一些事情来禁用隐式转换。一种方法是搞乱构造函数以防止它们接受隐式转换,并强制它们严格接受相应的类型:

(现场演示)

#include <type_traits>

// ...

    template<typename T, typename=std::enable_if_t<std::is_same_v<T, bool>>>
    Bool(const T &val) : m_value(val) {}

// ...

    template<typename T, typename=std::enable_if_t<std::is_same_v<T, int>>>
    Int(const T &val) : m_value(val) {}

现在,

Bool
的构造函数将无法重载解析,除非其参数是真实的、真实的
bool
,而
Int
的构造函数将无法重载解析,除非其参数是真实的、真实的
int

请注意,这也可以防止

char
long
和其他整数挤过。一种可能的变体是
!std::is_same_v<T,bool>
,您可能想尝试一下。

© www.soinside.com 2019 - 2024. All rights reserved.