Использование варианта буста с вычетом шаблона - PullRequest
1 голос
/ 30 апреля 2020

Рассмотрим следующий класс:

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);

Этот код работает и делает то, что я хочу, но я бы очень хотел Избегайте необходимости указывать тип шаблона в векторе. IE, я хочу быть в состоянии сделать это:

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>> &'

Похоже, что может неявно приведение типа функции к варианту этого типа функции? Кажется, это работает лучше без вектора, но разве я не смогу это сделать?

Спасибо,

Райан

Ответы [ 3 ]

1 голос
/ 30 апреля 2020

Вы можете взять initializer_list из FunctionVariantType:

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.

1 голос
/ 30 апреля 2020

Даже если A конвертируется в B, std::vector<A> не конвертируется в std::vector<B>.

Но вы можете легко построить std::vector<B> из std::vector<A> с помощью конструктора итератора:

auto vec = std::vector({&SomeOtherClass::someFunc});
auto classInstance = myClass<SomeOtherClass>({vec.begin(), vec.end()});
0 голосов
/ 30 апреля 2020

Если вы абсолютно ДОЛЖНЫ go пройти через эту промежуточную переменную vec, то я думаю, что лучший способ справиться с этим - немного подержать компилятор за руку и провести его по процессу.

В вашем конкретном случае c я бы go рассказал об этом в общих чертах:


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);
...