【问题标题】:Provide a operator== for std::variant为 std::variant 提供 operator==
【发布时间】:2020-07-03 04:13:04
【问题描述】:

我正在尝试为地图中定义的std::variant 创建一个operator== 运算符,如下所示:

struct anyType 
{
   template<typename T>
   void operator()(T t) const { std::cout << t; }
   void operator()(const std::string& s) const { std::cout << '\"' << s << '\"'; }
};

template<typename T>
bool operator==(const std::variant<float, int, bool, std::string>& v, const& T t) 
{
   return v == t;
}

int main()
{
   std::map<std::string, std::variant<float, int, bool, std::string>> kwargs;
   kwargs["interface"] = "linear"s;
   kwargs["flag"] = true;
   kwargs["height"] = 5;
   kwargs["length"] = 6;
   //test 
   if (kwarg["interface"] == "linear") // stack overflow Error here 
   { 
      std::cout << true << '\n';
   }
   else
   {
      std::cout << false << '\n';
   }
}

谁能告诉我为什么我的接线员不工作?

【问题讨论】:

  • 你的 operator== 什么都不做,只是递归调用自己

标签: c++ operator-overloading c++17 stdmap std-variant


【解决方案1】:

您的代码中有几个问题:

  • 您的operator== 中的const &amp;T t 应为T const&amp; tconst T&amp; t

  • 您忘记提及要与 std::string 不在 if 语句中使用 char 数组(即 "linear")。意思是你 需要以下任一项:

    if (kwargs["interface"] == std::string{ "linear" })
    // or 
    using namespace std::string_literals;
    if (kwargs["interface"] == "linear"s)  // since C++14
    
  • 当你像这样进行比较时

    if (kwargs["interface"] == "linear") // checking std::variant == char [7] 
    

    您正在检查std::variant&lt;float, int, bool, std::string&gt;(即v)类型为char [7](即linear 类型)。 当条件达到operator== 的定义时,您再次执行 同样的

    return v == t; // checking std::variant == char [7] 
    

    这会导致对模板化 operator== 本身的递归调用 因此堆栈溢出。


为了修复,您需要strong text通过索引或类型明确指定变体中的值。例如,使用std::is_sameif constexpr 来检查类型:

(See live online)

#include <type_traits> std::is_same_v

template<typename T>
bool operator==(const std::variant<float, int, bool, std::string>& v, T const& t)
{
   if constexpr (std::is_same_v<T, float>)            // float    
      return std::get<float>(v) == t;        
   else if constexpr (std::is_same_v<T, int>)         // int
      return std::get<int>(v) == t;
   else if constexpr (std::is_same_v<T, bool>)        // boolean
      return std::get<bool>(v) == t;
   else if constexpr (std::is_same_v<T, std::string>) // std::string
      return std::get<std::string>(v) == t;
}

或者简单地说(学分@Barry

template<typename T>
bool operator==(const std::variant<float, int, bool, std::string>& v, T const& t)
{
   return std::get<T>(v) == t;
}

现在,如果您传递除 v 包含之外的任何其他类型,您将收到模板化 operator== 的编译时错误。


通用解决方案!

对于通用std::varaint&lt;Types...&gt;,可以执行以下操作。此外,SFINAE 仅用于传递的 std::variant&lt;Types&gt; 中的那些类型。我用过is_one_of trait from this post

(See Live Online)

#include <variant>
#include <type_traits>

// A trait to check that T is one of 'Types...'
template <typename T, typename...Types>
struct is_one_of final : std::disjunction<std::is_same<T, Types>...> {};

template<typename... Types, typename T>
auto operator==(const std::variant<Types...>& v, T const& t) noexcept
   -> std::enable_if_t<is_one_of<T, Types...>::value, bool>
{
   return std::get<T>(v) == t;
}

【讨论】:

  • 嵌套的 if constexpr/get 链归结为 return std::get&lt;T&gt;(v) == t;
猜你喜欢
  • 2017-08-15
  • 1970-01-01
  • 2023-02-02
  • 1970-01-01
  • 2014-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-14
相关资源
最近更新 更多