【问题标题】:Determining number of arguments of C++ template functor确定 C++ 模板函子的参数数量
【发布时间】:2012-05-11 19:48:54
【问题描述】:

假设我们有:

template<typename F, typename T1, typename T2>
void my_magic_method(F func, T1 t1, T2 t2)
{
    if (???)
        func(t1);
    else
        func(t1,t2);
}

什么可以帮助我确定:

  1. 参数数量

  2. 每个参数的可能类型

  3. 返回值类型

由于 MSVS 2010,我无法使用可变参数模板...

更新

我的第一个解决方案:

template<typename F>
auto my_magic_func(F f) -> decltype(f(1))
{
    return f(1);
}

template<typename F>
auto my_magic_func(F f, void * fake = NULL) -> decltype(f(2,3))
{
    return f(2,3);
}

int main()
{
    auto x1 = my_magic_func([](int a){ return a+100; });
    auto x2 = my_magic_func([](int a, int b){ return a*b; });
    // x1 == 1+100
    // x2 == 2*3
}

这就是我的函数类型重载方式。 它有效,但也许是更好的解决方案?

【问题讨论】:

    标签: c++ visual-studio-2010 templates visual-c++ c++11


    【解决方案1】:

    不完全符合您的要求,但如果我正确理解您的意图,在 VC++ 2010 中,通过基于 arity 的简单重载是可能的(但很难看):

    #include <utility>
    #include <string>
    #include <iostream>
    
    template<typename F, typename T1>
    auto my_magic_method(F&& func, T1&& t1) ->
        decltype(std::forward<F>(func)(std::forward<T1>(t1)))
    {
        return std::forward<F>(func)(std::forward<T1>(t1));
    }
    
    template<typename F, typename T1, typename T2>
    auto my_magic_method(F&& func, T1&& t1, T2&& t2) ->
        decltype(std::forward<F>(func)(std::forward<T1>(t1), std::forward<T2>(t2)))
    {
        return std::forward<F>(func)(std::forward<T1>(t1), std::forward<T2>(t2));
    }
    
    struct string_to_float_functor
    {
        float operator ()(std::string const& s) const
        {
            return std::stof(s);
        }
    };
    
    int main()
    {
        auto a = my_magic_method([](std::string const& x) { return x + x; }, "foo");
        auto b = my_magic_method([](double x, int y) { return x * y; }, 21.5, 3);
        auto c = my_magic_method(string_to_float_functor(), "3.14159265");
        std::cout << a << '\n' << b << '\n' << c << '\n';
    }
    

    这支持一元和二元仿函数 - 继续该模式并根据需要为其他元数添加重载。

    【讨论】:

    • 我的问题是确定类型名 F 的参数数量。您的解决方案有 2 个不同的 my_magic_funcs 用于确定。与我的问题相比,我目前的问题太复杂了。这只是其中的一部分。
    • @k06a :你的问题是XY problem——如果你说的是你想要完成的事情,而不是你如何尝试(和失败)来完成它,那会很多更容易为您提供帮助。
    • @k06a:那么,如果这不是您想要回答的问题,您为什么要这个问题?您为什么不尝试询问您真正想要解决的问题,而不是询问您关心的不同的、更简单的解决方案?
    【解决方案2】:

    这里有一些方法;都假设 C++11。使用 -std=c++11 在 clang++ 3.2 上测试。

    //Taking a function pointer argument (template types inferred)
    
    template <typename ret, typename ... Args>
    constexpr int arg_count(ret (*f)(Args...)) {
        return sizeof...(Args);
    }
    
    //Taking a function type (or related) directly
    
    template <typename T>
    struct ArgCount {
        static const int value = 0;
    };
    
    template <typename Ret, typename ... Args>
    struct ArgCount<Ret(Args...)> {
        static const int value = sizeof...(Args);
    };
    
    template <typename Ret, typename ... Args>
    struct ArgCount<Ret(*)(Args...)> {
        static const int value = sizeof...(Args);
    };
    
    template <typename Ret, typename ... Args>
    struct ArgCount<Ret(&)(Args...)> {
        static const int value = sizeof...(Args);
    };
    
    //Using the latter for dispatch
    
    template <int N>
    struct helper {
        template<typename F, typename T1, typename T2>
        static void call(F func, T1 t1, T2 t2);
    };
    
    template <>
    struct helper<1> {
        template<typename F, typename T1, typename T2>
        static void call(F func, T1 t1, T2 t2) {
            func(t1);
        }
    };
    
    template <>
    struct helper<2> {
        template<typename F, typename T1, typename T2>
        static void call(F func, T1 t1, T2 t2) {
            func(t1, t2);
        }
    };
    
    template<typename F, typename T1, typename T2>
    void my_magic_method(F func, T1 t1, T2 t2)
    {
        helper<ArgCount<F>::value>::call(func, t1, t2);
    }
    
    //Testing
    
    #include <cstdio>
    
    void a(int a, int b) { printf("%i\n", a + b); }
    void b(int x) { printf("%i\n", x); }
    
    int main() {
        printf("%i %i\n", arg_count(a), arg_count(b));
        printf("%i %i\n", ArgCount<decltype(a)>::value, ArgCount<decltype(b)>::value);
        my_magic_method(a, 1, 2);
        my_magic_method(b, 1, 2);
    }
    

    【讨论】:

    • 我认为您应该更多地解释为什么要这样做,以便 OP 完全理解您的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-14
    • 2016-04-02
    • 2020-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多