代码之家  ›  专栏  ›  技术社区  ›  Ed The ''Pro'' Simon Klee

确定函数参数是否为函数

  •  1
  • Ed The ''Pro'' Simon Klee  · 技术社区  · 6 年前

    如何确定函数的参数 类型 是一个 功能 是吗?我正在实现一个名为 Queue 它接收一个参数。如果参数是函数,则存储该函数。

    代码如下:

    template <class Type, typename Data>
    class Queue {
        public:
            void Enqueue (Data& data) {
                if (typeid(data).name() == int) {
                    intVector.push_back(data);
                    order.push_back("int");
                }
                else if (typeid(data).name() == bool) {
                    boolVector.push_back(data);
                    order.push_back("bool");
                }
                else if (typeid().name() == string) {  
                  stringVector.push_back(data);
                  order.push_back("string");
                }
                // This will continue for:
                // - double
                // - char
                // - function
            }
    
            auto Dequeue () {
                auto temp;
                switch (order.begin()) {
                    case "int":
                        temp = intVector.begin();
                        intVector.erase(intVector.begin());
                        order.erase(order.begin());
                        return temp;
                    // This will continue for:
                    // - "string"
                    // - "bool"
                    // - "char"
                    // - "double"
                    // - "function"
                    default:
                        cout << "An Error occurred while trying to Enqueue." << endl;
                        cout << "\tAddress: " << this << endl;
                }
            }
    
            auto Start () {
                // This function will run all of the processes...
            }
            Queue (Data& data) {
                if (typeid(Type).name() == int) {
                    // Pseodo-code:
                    // if (data.type == function) {
                    //     Enqueue (data);
                    // }
                }
            }
    }
    

    它可以初始化:

    Queue queue1 = new Queue <int> (func ()); // func () is a function.
    Queue queue2 = new Queue <int> (var);     // var is a variable.
    
    4 回复  |  直到 6 年前
        1
  •  2
  •   Ed The ''Pro'' Simon Klee    6 年前

    哦,天哪。这有点 XY problem 是的。

    不管怎样,在搞乱之后 std::enable_if 有一段时间(有点好玩),我意识到整个事情可以归结为:

    #include <vector>
    #include <string>
    #include <any>
    #include <iostream>
    #include <functional>
    
    void call_if_function (void (* f) ()) { f (); }
    void call_if_function (std::function <void ()> f) { f (); }
    void call_if_function (std::any x) { (void) x; }
    
    template <class T>
    class Queue
    {
        public:
            void Enqueue (const T& data)
            {
    //          std::cout << "Enqueueing " << data << "\n";
                v.push_back (data);
            }
    
            T Dequeue ()
            {
                T ret = v.front ();
    //          std::cout << "Dequeueing " << ret << "\n";
                v.erase (v.begin ());
                call_if_function (ret);
                return ret;
            }
    
        private:
            std::vector <T> v;
    };
    

    如果我理解手术的问题,那就是你所需要的。

    测试程序:

    void foo () { std::cout << "foo () called\n"; }
    void bar (int x, int y) { std::cout << "bar () called, x = " << x << ", y = " << y << "\n"; }
    
    int main ()
    {
        // Queue of int's
        Queue <int> int_q;
        int_q.Enqueue (42);
        auto i = int_q.Dequeue ();
        std::cout << "int_q.Dequeue () returned " << i << "\n\n";
    
        // Queue of strings
        Queue <std::string> string_q;
        string_q.Enqueue ("Hello world");
        auto s = string_q.Dequeue ();
        std::cout << "string_q.Dequeue () returned " << s << "\n\n";
    
        // Call function with no parameters    
        Queue <void (*)()> func_q;
        func_q.Enqueue (foo);
        auto f = func_q.Dequeue ();
        std::cout << "func_q.Dequeue () returned " << (void *) f << "\n";
        f ();
    
        // Call function with arbitrary parameters
        Queue <std::function <void ()>> func_qp;
        func_qp.Enqueue ([] () { bar (21, 99); });
        auto fp = func_qp.Dequeue ();
        fp ();
    }
    

    输出:

    int_q.Dequeue () returned 42
    
    string_q.Dequeue () returned Hello world
    
    foo () called
    func_q.Dequeue () returned 0x4026fd
    foo () called
    
    bar () called, x = 21, y = 99
    bar () called, x = 21, y = 99
    

    Live demo 是的。

    寓意:亲,这年头玩具盒里的玩具太多了。享受周末的人们。

        2
  •  2
  •   Ashley Mills    6 年前

    而且,由于我花了点时间研究它(主要是因为我想了解一点),这里有一个超级简单的sfinae拼凑而成 the wise ones 是的。

    #include <type_traits>
    #include <iostream>
    
    // Primary template (required)
    template <class T, class Enable = void>
    struct X { };
    
    // Specialisation to take a function pointer
    template <class T>
    struct X <T, typename std::enable_if <std::is_function<T>::value>::type>
    {
        X (T func)
        {
            std::cout << "T is a function\n";
            func ();
        }
    };
    
    // Partial specialisation for anything else
    template<class T>
    struct X <T, typename std::enable_if <!std::is_function<T>::value>::type>
    {
        X (T x)
        {
            std::cout << "T is not a function (and x is " << x << ")\n";
        }
    };
    
    void foo () { std::cout << "foo () called\n"; }
    
    int main ()
    {
        X <void ()> x1 (foo);
        X <int> x2 (42);
    }
    

    输出:

    T is a function
    foo () called
    T is not a function (and x is 42)
    

    Live demo 是的。

    强大的东西,但不是每个小问题的答案。

        3
  •  1
  •   πάντα ῥεῖ    6 年前

    如何确定函数的参数类型是否为函数?

    你可以使用 std::is_function 这样做。

    像这样的实现

    template <class Type, typename Data>
    class Queue {
        public:
            Queue (Data& data) {
                if (typeid(Type).name() == int) {
                    // Pseodo-code:
                    if (std::is_function<data.type>::value) {
                         Enqueue (data);
                    }
                }
            }
    }
    

    但不会起作用,因为里面的部分 if 编译器可以看到其他数据类型的块作用域。

    意识到你需要使用 SFINAE ,并提供 Queue 构造函数使用 std::enable_if 是的。

        4
  •  -1
  •   MivVG    6 年前

    对于sfinae示例:

    Queue(std::enable_if_t<std::is_function_v<Data>, Data>::type & data)
    {
        //data is a function
    }
    
    //I'm not sure if the enable_if is needed here, maybe you can just do Data& data
    Queue(std::enable_if_t<!std::is_function_v<Data>, Data>::type & data)
    {
        //data is not a function
    }
    

    (你需要包括 <type_traits> 使用 std::is_function_v )