Не удается заставить механизм обнаружения существования метода работать

#c #c 14 #template-meta-programming #conditional-compilation

#c #c 14 #шаблон-мета-программирование #условная компиляция

Вопрос:

Я пишу шаблонный код, который должен вызывать определенный шаблон operator() функторов, который он получает, но только если он operator() существует.

Я написал следующий код:

 
template <typename>
struct sfinae_true : std::true_type{};

template <class F, typename T, typename... Us>
static auto test_templated_invoke_operator(int) ->
    sfinae_true<decltype(std::declval<F>().template operator()<T>(std::forward(std::declval<Us>())... ))>;

template <class, typename, typename... Us>
static auto test_templated_invoke_operator(long) -> std::false_type;

template <class F, typename T, typename... Us>
struct has_templated_invoke_operator : decltype( test_templated_invoke_operator<F, T, Us...>(int{}) )
{ };

template <bool ActuallyInvoke, typename R, class F, typename T, typename... Ts>
struct invoke_if_possible_inner;

template <class F, typename R, typename T, typename... Ts>
struct invoke_if_possible_inner<false, R, F, T, Ts...>
{
    R operator()(F, Tsamp;amp;...) { 
        return R(); 
    }
};

template <class F, typename R, typename T, typename... Ts>
struct invoke_if_possible_inner<true, R, F, T, Ts...>
{
    R operator()(F functor, Tsamp;amp;... params)
    {
        return functor.template operator()<T>(std::forward<Ts>(params)...);
    }
};

template <typename T, typename R>
struct invoke_if_possible {
    template <class F, typename... Ts>
    R operator()(F functor, Tsamp;amp;... params)
    {
        constexpr bool actually_invoke = has_templated_invoke_operator<F, T, Ts...>::value;
        // static_assert(actually_invoke == true,"Should be able to invoke for now!");
        return invoke_if_possible_inner<actually_invoke, R, F, T, Ts...>{}(functor, std::forward<Ts>(params)...);
    }
};
  

и вот небольшая main() функция для ее тестирования:

 int main() 
{
    invoke_if_possible<int, double> iip;
    auto result = iip(foo{}, 3.0);
    std::cout << "Invoke if possible result is " << result << " (and should be 6.0)" << std::endl;
}
  

Сбой (Coliru) — возврат 0.0 вместо 6.0.

Мой вопрос: почему код не вызывает определенный operator() ? И как я могу исправить механизм обнаружения, чтобы его существование было подтверждено и оно вызывалось?

Примечания:

  • Параметр шаблона T является произвольным; он не имеет ничего общего с Us параметрами.
  • Да, можно получить R, используя возвращаемый тип для operator() — но только если он существует. Поэтому мы просто предоставляем его.
  • Если вы включите статическое утверждение — оно завершается с ошибкой.

Ответ №1:

Ваша проблема здесь:

 std::forward(std::declval<Us>())
  

std::forward принимает не выводимый параметр шаблона, который вы не предоставляете — должен быть forward<T>(u) — поэтому его вывод безоговорочно завершается неудачей.

Но вам даже не нужно forward здесь вообще. declval<Us>() Достаточно просто.