【问题标题】:Using boost variant with template deduction使用带有模板推导的 boost 变体
【发布时间】:2020-08-15 02:49:38
【问题描述】:

考虑以下类:

template <typename classTypeT>
class myClass {
public:    
    using FunctionType1 = std::function<void(classTypeT &, const std::string*)>;
    using FunctionType2 = std::function<void(classTypeT &, const int)>;
    using FunctionVariantType = boost::variant<FunctionType1, FunctionType2>;

    std::vector<FunctionVariantType> myVariants;

    myClass(const std::vector<FunctionVariantType> myVec) {
        myVariants = myVec;
    }
};

并创建该类的实例:

auto vec = std::vector<myClass<SomeOtherClass>::FunctionVariantType>({&SomeOtherClass::someFunc});
auto classInstance = myClass<SomeOtherClass>(vec);

这段代码可以工作并且可以做我想做的事,但我真的很想避免在向量中指定模板类型。即,我希望能够做到这一点:

auto vec = std::vector({&SomeOtherClass::someFunc});
auto classInstance = myClass<SomeOtherClass>(vec); // Error

并且有一些模板推导,但我收到这样的错误:

cannot convert argument 1 from 'std::vector<void (__cdecl myClass::* )(const std::string *),std::allocator<_Ty>>' to 'const std::vector<mwboost::variant<std::function<void (classTypeT &,const std::string *)>,std::function<void (classTypeT &, const int)>>,std::allocator<_Ty>> &'

看起来它不能将函数类型隐式转换为该函数类型的变体?如果没有矢量,这似乎效果更好,但我不应该仍然能够做到这一点吗?

谢谢,

瑞恩

【问题讨论】:

  • 在完全隔离的情况下查看auto vec = std::vector({&amp;SomeOtherClass::someFunc}); 行。应该如何知道boost::variantstd::function 的那行代码会在这里涉及?或者换句话说:如果您是编译器,您会将auto 替换为哪种类型?

标签: c++ class templates vector template-argument-deduction


【解决方案1】:

您可以选择initializer_listFunctionVariantType

template <typename T>
class myClass {
public:
    using FunctionType1 = std::function<void(T&, const std::string*)>;
    using FunctionType2 = std::function<void(T&, const int)>;
    using FunctionVariantType = std::variant<FunctionType1, FunctionType2>;

    std::vector<FunctionVariantType> myVariants;

    myClass(std::initializer_list<FunctionVariantType> myVec)
        : myVariants(myVec) {}
};

int main()
{
    auto func1 = [](int&, const std::string*) {};
    auto func2 = [](int&, const int) {};

    myClass<int> myInst({func1, func2});
}

这是因为vector 也有一个构造函数采用initializer_list

【讨论】:

  • 这最终是一个比我试图用向量做的更好的方法。谢谢!
  • @rmsantos:这与您的方法相同。你的问题是使用中间变量而不是直接在构造函数中使用{func1, func2}
【解决方案2】:

如果您绝对必须通过该中间 vec 变量,那么我认为解决此问题的最佳方法是稍微握住编译器并引导它完成整个过程。

在您的具体情况下,我会按照以下一般思路进行处理:


template <typename classTypeT>
class myClass {
public:
  [...]

  template<typename... Args>
  static auto make_vtable(Args&&... args) {
     return std::vector<FunctionVariantType>({std::forward<Args>(args)...});
  }
}

并创建一个类的实例:

using class_type = myClass<SomeOtherClass>;

auto vec = class_type::make_vtable(&SomeOtherClass::someFunc, &SomeOtherClass::someOtherFunc);
auto classInstance = class_type(vec);

【讨论】:

    【解决方案3】:

    即使A 可以转换为Bstd::vector&lt;A&gt; 也不能转换为std::vector&lt;B&gt;

    但是您可以使用迭代器构造函数从std::vector&lt;A&gt; 轻松构造std::vector&lt;B&gt;

    auto vec = std::vector({&SomeOtherClass::someFunc});
    auto classInstance = myClass<SomeOtherClass>({vec.begin(), vec.end()});
    

    【讨论】:

    • 我认为这不适用于 OP,因为他们几乎肯定首先希望 vec 是异构的。
    • @Frank:OP 仍然可以省略vec 变量并直接执行myClass&lt;SomeOtherClass&gt;({&amp; func1, &amp;func2, &amp; func3});
    • 是的,很明显,我有点假设通过 vec 的间接性是一个硬性要求,但如果不是这样,那会让这更简单。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多