Как получить тип шаблона в аргументах std :: function с помощью лямбды?

У меня есть повышение :: вариант, и я хотел бы выполнить функтор, только если вариант имеет специальный тип, поэтому я составил эту функцию:

template<typename T, typename Variant>
void if_init(Variant& opt_variant, std::function<void(T)> functor){
if(auto* ptr = boost::get<T>(&opt_variant)){
functor(*ptr);
}
}

Это хорошо работает, но я бы хотел, чтобы выводился тип T, чтобы я мог написать это:

if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; });

Но тип не выводится:

type_inference.cpp:19:5: error: no matching function for call to 'if_init'
if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
^~~~~~~
type_inference.cpp:10:6: note: candidate template ignored: failed template argument deduction
void if_init(Variant& opt_variant, std::function<void(T)> functor){

Если я напишу:

if_init<double>(b, [](double var){ std::cout << "I'm double and set" << std::endl; });

это работает хорошо.

Есть ли способ сделать тип T выводимым? Я хотел бы набрать T только один раз. Здесь тип короткий, но в реальном случае это длинные типы.

Я использую CLang 3.2.

Вот полный тестовый пример (первый вызов компилируется, а не второй):

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

typedef boost::variant<int, double> Test;

template<typename T, typename Variant>
void if_init(Variant& opt_variant, std::function<void(T)> functor){
if(auto* ptr = boost::get<T>(&opt_variant)){
functor(*ptr);
}
}

int main(){
Test b = 1.44;

if_init<double>(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
if_init(b, [](int var){ std::cout << "I'm int and set" << std::endl; });

return 0;
}

3

Решение

Я рекомендую вам подумать о std::function<Sig> в качестве контейнера любого одного функтора, который соответствует Sig в качестве подписи — и который может быть заменен в любой момент. Эта функция очень удобна, например, для std::vector<std::function<Sig>> потому что такой контейнер может содержать функторы разные типы.

В вашем случае, потому что вам нужен только один функтор, который вам действительно не нужен std::function<Sig>, Поэтому я рекомендую вам объявить шаблон вашей функции следующим образом:

template<typename T, typename Variant, typename Functor>
void if_init(Variant& opt_variant, Functor functor);

Если вы беспокоитесь, что это не значит, что Functor должен соответствовать void(T) подпись, пожалуйста, обратите внимание, что std::function<Sig> делает не обеспечить это либо: хотя, очевидно, вы будут в конечном итоге с ошибкой компиляции, это не очень хорошо. Его планируется изменить (и, возможно, ваша реализация тоже), но поменять на другой тип ошибки. Все еще не очень полезно для вашего случая.

Я лично использую псевдонимы шаблона (в списке параметров шаблона) как документировать и применять то, что функтору должно соответствовать. Это в конечном итоге выглядит как:

// Documents that e.g. long l = std::forward<Functor>(functor)(42.)
// should be a valid expression -- a functor that returns int would
// also be accepted.
// Triggers a hard-error (typically a static_assert with a nice message)
// on violation.
template<typename Functor, Requires<is_callable<Functor, long(double)>>...>
R foo(Functor functor);

// Documents that this function template only participates in overload resolution
// if the functor conforms to the signature.
// Does not trigger a hard-error (necessary by design); if everything goes right
// then another overload should be picked up -- otherwise an error of the kind
// 'no matching overload found' is produced
template<typename Functor, EnableIf<is_callable<Functor, long(double)>>...>
R bar(Functor functor);

Что касается вашего точный вопрос, правила C ++ не позволяют выводить параметр шаблона в вашем случае. Это действительно не легко решаемая «проблема», если она есть. Ты можешь найти Дополнительная информация на этом.

6

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]