【问题标题】:Same template class specialization for std::variant and boost::variant template typesstd::variant 和 boost::variant 模板类型的相同模板类特化
【发布时间】:2022-07-08 20:41:45
【问题描述】:

如果通过任何 std::variant 或任何 boost::variant,我想创建一个具有相同实现的类专业化。我试图玩弄 std::enable_if、std::disjunction 和 std::is_same 但我无法让它编译。这是一个代码示例,用于显示我想要实现的目标。

#include <variant>
#include <iostream>
#include <boost/variant.hpp>

template <typename T>
struct TypeChecker;

template <typename T>
struct TypeChecker<T>
{
    void operator()()
    {
        std::cout << \"I am other type\\n\";
    }
}

template <typename ... Ts>  // I want to be able to capture Ts... in TypeChecker scope
struct TypeChecker<std::variant<Ts...> or boost::variant<Ts...>> // what to insert here?
{
    void operator()()
    {
        std::cout << \"I am either std::variant or boost::variant\\n\";
    }
}

int main()
{
    TypeChecker<std::variant<int, float>>{}();
    TypeChecker<boost::variant<int, float>>{}();
    TypeChecker<int>{}();
}

预期结果:

I am either std::variant or boost::variant
I am either std::variant or boost::variant
I am other type
  • C++ 中没有 or 关键字/运算符
  • @JakobStark C++ 中有or keyword,它是|| 的同义词,但如果没有一些元编程,它不能在这里直接使用。
  • @Yksisarvinen 我实际上不知道这一点,以前从未见过。感谢您指出;)

标签: c++ templates metaprogramming variant


【解决方案1】:

您可以使用 template template parameter 例如像这样

template <typename T>
struct TypeChecker {
    void operator()() {
        std::cout << "I am other type\n";
    }
};

template<typename ... Ts, template<typename...> typename V>
requires std::same_as<V<Ts...>, std::variant<Ts...>> ||
         std::same_as<V<Ts...>, boost::variant<Ts...>>
struct TypeChecker<V<Ts...>>
{
    void operator()()
    {
        std::cout << "I am either std::variant or boost::variant\n";
    }
};

请注意,这使用 C++20 约束。如果您不能使用 C++20,您可以使用 std::enable_if 代替,例如这个:

template<typename ... Ts, template<typename...> typename V>
struct TypeChecker<V<Ts...>> : std::enable_if_t<
        std::is_same_v<V<Ts...>, std::variant<Ts...>> ||
        std::is_same_v<V<Ts...>, boost::variant<Ts...>>, std::true_type>
{
    void operator()()
    {
        std::cout << "I am either std::variant or boost::variant\n";
    }
};

你可以在godbolt 上看到它。

【讨论】:

  • 我喜欢这个 pre-c++20 的解决方案,简单而且没有太多额外的代码,谢谢!
【解决方案2】:

这个想法是创建一个“调度程序”类,即添加另一个间接级别。虽然这仍然需要一些代码,但您不必为每个函数重新实现它:

#include <variant>
#include <iostream>
#include <boost/variant.hpp>

template <typename T, typename... Ts>
struct TypeCheckerOther
{
    void operator()()
    {
        std::cout << "I am other type\n";
    }
};

template <typename T, typename... Ts>
struct TypeCheckerVariant
{
    void operator()()
    {
        std::cout << "I am either std::variant or boost::variant\n";
    }
};

template <typename T>
struct TypeCheckerImpl
{
    using type = TypeCheckerOther<T>;
};

template <typename... Ts>
struct TypeCheckerImpl<std::variant<Ts...>>
{
    using type = TypeCheckerVariant<std::variant<Ts...>, Ts...>;
};

template <typename... Ts>
struct TypeCheckerImpl<boost::variant<Ts...>>
{
    using type = TypeCheckerVariant<boost::variant<Ts...>, Ts...>;
};

template<typename T>
using TypeChecker = typename TypeCheckerImpl<T>::type;


int main()
{
    TypeChecker<std::variant<int, float>>{}();
    TypeChecker<boost::variant<int, float>>{}();
    TypeChecker<int>{}();
}

【讨论】:

    【解决方案3】:

    std::eneble_ifstd::same_as 很酷,但在某些情况下,旧的经典方式看起来更好:

    template <typename T>
    struct is_any_variant : std::false_type {};
    
    template <typename ...Ts>
    struct is_any_variant<std::variant<Ts...>> : std::true_type {};
    
    template <typename ...Ts>
    struct is_any_variant<boost::variant<Ts...>> : std::true_type {};
    
    template <typename T>
    constexpr bool is_any_variant_v = is_any_variant<T>::value;
    

    Live demo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-17
      相关资源
      最近更新 更多