1
class EG
{
template<class T>
std::function<void(T)> f;

//these are supposed to be appropriate instantiations that I have to look up how to do as I haven't really used templates
template<std::string> f;
template<int> f;

template<class T>
void func(std::function<void(T)>&& arg)
{
f<std::string> = nullptr;
f<int> = nullptr;
f.swap(arg);
}

};

这就是我要做的。

EG eg;
eg.func([](std::string s){});
eg.func([](int i){});

有一个回调缓存 (f),它可以采用不同的参数(指向对象的指针、位置向量等)。它用于模拟程序中的鼠标定位。当我开始另一个目标进度时,我需要取消当前目标(这意味着现在 f = null)。我只是不想要很多实际上做同样事情的函数和成员(但对于不同的论点)。我怎么解决这个问题?

我可以简单地检查是否有一个带有 bool 而不是 f == null 的目标,但对于不同的回调参数,我仍然需要多个 f 实例)。使用 bool 而不是 f == nullptr 检查将阻止我拥有模板类。检查 f == nullptr 是否也会阻止我使用模板类。

有关此案的更多信息:

这实际上是一个回调处理程序,并且 T 只有两种不同的类型在使用(当前)。

我试图防止有多个 f1、f2... 和 void func 变体。

4

1 回答 1

1

评论有点长,所以我将其发布为答案:

class EG
{
    template<class T>
    std::function<void(T)> f;  // a data member template?

    template<class T>
    void func(std::function<void(T)>&& arg)
    {
        f = nullptr;
        f.swap(arg);
        // could as well just
        // f = std::move(arg);
    }
};

如果您的用例是:

EG obj;

obj.func( [](int i) { std::cout << i; } );
obj.f(42);

obj.func( [](string s) { std::cout << s; } );
obj.f("hello world");

这很容易出错,因为编译器无法检查函数调用obj.f的参数类型,因为参数类型应该是可变的:如果你分配一个void(int)via obj.func,那么它应该接受一个 int;如果您分配 a void(string),它将接受一个字符串。

C++ 中没有数据成员模板(IMO 拥有它们没有意义——何时应该实例化它们?),但可以获得上述用例的行为。


一个更简单、不易出错的解决方案:

#include <functional>
#include <string>
#include <iostream>
#include <memory>

using std::string;

struct any_function
{
    virtual ~any_function()
    {}
};
template < typename T >
struct concrete_function
    : public any_function
{
    T m;
    concrete_function(T&& p)
        : m( std::move(p) )
    {}
    virtual ~concrete_function() override
    {}
};

struct EG
{
private:
    std::shared_ptr<any_function> fs;

public:
    EG& operator=(std::function<void(int)>&& p) // do NOT templatize this!!!!
    {
        using stor_type = concrete_function< std::function<void(int)> >;
        fs = std::make_shared<stor_type>( std::move(p) );
        return *this;
    }
    EG& operator=(std::function<void(string)>&& p) // do NOT templatize this!!!!
    {
        using stor_type = concrete_function< std::function<void(string)> >;
        fs = std::make_shared<stor_type>( std::move(p) );
        return *this;
    }

    void operator()(int p) // do NOT templatize this!!!!
    {
        using stor_type = concrete_function< std::function<void(int)> >;
        auto const& ptr = std::static_pointer_cast< stor_type >(fs);
        if(ptr) {  ptr->m(p);  }
        else { /* throw something */ }
    }
    void operator()(string p) // do NOT templatize this!!!!
    {
        using stor_type = concrete_function< std::function<void(string)> >;
        auto const& ptr = std::static_pointer_cast< stor_type >(fs);
        if(ptr) {  ptr->m(p);  }
        else { /* throw something */ }
    }
};


int main()
{
    EG obj;

    obj = [](int i) { std::cout << i; };
    obj(42);       // using overload mechanism
}

您不应将标记的函数模板化,因为创建 ( ) 中使用的类型必须与调用 ( ) 中使用的类型完全make_shared匹配。static_pointer_cast

或者,使用枚举:

#include <functional>
#include <string>
#include <iostream>

using std::string;

struct EG
{
    enum stored_function_type
    {
        INT_FUNC, STRING_FUNC
    };

    union function_storage
    {
        std::function<void(int)> f_int;
        std::function<void(string)> f_string;

        function_storage()
             : f_int()
        {}
        ~function_storage()
        {}
    };

    stored_function_type ft;
    function_storage fs;

    template < typename T >  void destroy(T& p)  {  p.~T();  }
    void destroy()
    {
        switch(ft)
        {
        case INT_FUNC:
            destroy(fs.f_int);
        break;
        case STRING_FUNC:
            destroy(fs.f_string);
        break;
        }
    }

    EG()
      : ft(INT_FUNC)
    {}
    ~EG()
    {
        destroy();
    }

    EG& operator=(std::function<void(int)>&& p)
    {
        destroy();
        new(&fs.f_int) std::function<void(int)>( std::move(p) );
        ft = INT_FUNC;

        return *this;
    }
    EG& operator=(std::function<void(string)>&& p)
    {
        destroy();
        new(&fs.f_string) std::function<void(string)>( std::move(p) );
        ft = STRING_FUNC;

        return *this;
    }

    void operator()(int p)
    {
        // better check ft == INT_FUNC
        return fs.f_int(p);
    }
    void operator()(string p)
    {
        // better check ft == STRING_FUNC
        return fs.f_string(p);
    }
};


int main()
{
    EG obj;

    obj = [](int i) { std::cout << i; };
    obj(42);       // using overload mechanism
}

您可以使用花哨的模板元编程为许多类型简化此操作。

免责声明:我已经很久没有使用unions.... 可能会错过一些东西。

于 2013-05-15T18:22:43.833 回答