无法使方法存在检测机制起作用
Can't get a method existence detection mechanism to work
我正在编写模板代码,需要调用它获得的某个模板 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, Ts&&...) {
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, Ts&&... 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, Ts&&... 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;
}
这个 fails (Coliru) - returning 0.0 而不是 6.0。
我的问题是:为什么代码不调用定义的 operator()?以及如何修复检测机制以确认其存在并调用它?
备注:
- 模板参数T是任意的;它与
Us
参数无关。
- 是的,可以使用
operator()
的 return 类型派生 R - 但前提是它存在。所以我们只提供它。
- 如果启用静态断言 - 它会失败。
您的问题在这里:
std::forward(std::declval<Us>())
std::forward
采用您未提供的非推导模板参数 - 必须是 forward<T>(u)
- 因此其推导无条件失败。
但是你根本不需要这里的 forward
。只需 declval<Us>()
就足够了。
我正在编写模板代码,需要调用它获得的某个模板 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, Ts&&...) {
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, Ts&&... 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, Ts&&... 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;
}
这个 fails (Coliru) - returning 0.0 而不是 6.0。
我的问题是:为什么代码不调用定义的 operator()?以及如何修复检测机制以确认其存在并调用它?
备注:
- 模板参数T是任意的;它与
Us
参数无关。 - 是的,可以使用
operator()
的 return 类型派生 R - 但前提是它存在。所以我们只提供它。 - 如果启用静态断言 - 它会失败。
您的问题在这里:
std::forward(std::declval<Us>())
std::forward
采用您未提供的非推导模板参数 - 必须是 forward<T>(u)
- 因此其推导无条件失败。
但是你根本不需要这里的 forward
。只需 declval<Us>()
就足够了。