当前位置: 首页 > 知识库问答 >
问题:

std::使用可变模板函数绑定

仲浩旷
2023-03-14

我试图编写一个通用的obj工厂,使用可变模板调用各种类的构造函数。代码如下:

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

template<typename T>
class ObjFactory {
public:
    typedef std::shared_ptr<T>              ObjPtr;
    typedef std::function<ObjPtr(void)>     CreatorFunc;
public:
    void registerCreator(const std::string &name, const CreatorFunc &creator)
    { m_dictCreator[name] = creator; }

    ObjPtr getObj(const std::string &name) const
    {
        auto it = m_dictCreator.find(name);
        return (it == m_dictCreator.end() ? nullptr : (it->second)());
    }
private:
    std::unordered_map<std::string, CreatorFunc>   m_dictCreator;
};


using namespace std;

struct Base {
    virtual ~Base() {}
    virtual void greet() const
    { cout << "I am Base" << endl; }
};

struct Derived : Base {
    Derived() : x(0), y(0) {}
    Derived(int a, int b) : x(a), y(b) {}
    int x, y;

    virtual void greet() const
    { cout << "I am Derived x = " << x << " y = " << y << endl; }
};

template<typename T, typename... Args>
std::shared_ptr<T> create_obj(Args... args)  // This OK
// std::shared_ptr<T> create_obj(Args&&... args) // WRONG
{ return std::make_shared<T>(std::forward<Args>(args)...); }

int main()
{
    ObjFactory<Base> factory;
    factory.registerCreator("default", create_obj<Derived>);
    factory.registerCreator("withArgs", std::bind(create_obj<Derived, int, int>, 1, 2));

    do {
        auto pObj = factory.getObj("default1");
        if (pObj) { pObj->greet(); }
    } while (0);

    do {
        auto pObj = factory.getObj("withArgs");
        if (pObj) { pObj->greet(); }
    } while (0);

    return 0;
}

在大多数例子中,变量arg总是这样写“Args”

错误:没有可行的转换从'__bind(

在移除“

但我不知道为什么?

共有2个答案

邴越彬
2023-03-14

当使用转发引用时,您需要让参数被推断出来,否则您无法完美地转发它们,因为您不知道用于它们的真正类型。

在您的案例中,您给出了一个类型create\u obj

您将可调用项分配给一个常量CreatorFunc

替换create_obj

真正的解决方案是使用lambda。

洪鸿
2023-03-14

通用参考仅在推导的上下文中起作用。当显式指定模板参数时,它们不会像您期望的那样工作。

给定函数模板

template <typename... Args>
void foo(Args&&... args) {}

还有那个电话

int a = 1;
int b = 2;
foo(a, b);

Args将被推断为{int

如果使用参数的右值调用它(即foo(1,2)),则Args将被推断为{int,int},并且Args中的值类型将变为{int>

这是通用引用的基础,现在让我们看看当你调用时会发生什么

auto fn = std::bind(foo<int, int>, 1, 2);
fn();

这里,您不允许进行模板参数推断,因此Args{int,int},因此foo需要{int>类型的参数

正确执行此操作的方法是使用lambda而不是std::bind

auto fn = []() { foo(1, 2); };
fn();

使用lambda时,模板参数推断工作正常,12保持右值。一切都按预期进行,通用引用也发挥了作用,因为它们是在推导的上下文中使用的。

 类似资料:
  • 我有两个变量类成员函数。当第一个被调用时,我想创建一个std::function到第二个类成员函数,然后将的参数绑定到函数指针。 所以稍后我可以调用,而不必将所有参数传递给 我想避免使它成为模板类,并将参数存储在元组中。 我试图让以下示例起作用: 链接到live示例:http://cpp.sh/4ylm 当我编译时,我得到一个错误 模板参数推断/替换失败:17:37: 注意:无法推断模板参数“\u

  • 多亏了C11,我们收到了系列的仿函数包装器。不幸的是,我一直只听到关于这些新添加的不好的消息。最受欢迎的是它们非常慢。我测试了它,与模板相比,它们真的很糟糕。 111毫秒对1241毫秒。我认为这是因为模板可以很好地内联,而通过虚拟调用覆盖内部。 显然,在我看来,模板也有其问题: 它们必须以头的形式提供,这不是您在以封闭代码形式发布库时可能不希望做的事情, 因此,我可以假设s可以用作传递函子的事实标

  • 在C++11之前,类模板和函数模板只能含有固定数量的模板参数。C++11增强了模板功能,允许模板定义中包含0到任意个模板参数,这就是可变参数模板。可变参数模板的加入使得C++11的功能变得更加强大,而由此也带来了许多神奇的用法。 可变参数模板 可变参数模板和普通模板的语义是一样的,只是写法上稍有区别,声明可变参数模板时需要在typename或class后面带上省略号...: template<ty

  • 我发现了和类型推导的以下行为,这对我来说是意想不到的: 中的两行都会导致错误: 没有函数模板“stdfunc_test”的实例与参数列表匹配 尝试在Visual Studio 2015中编译时。 为什么类型演绎不从函数类型中演绎模板类型,有没有变通方法?

  • 我目前有一个,但是为了灵活性,我希望能够分配一个lambda表达式,将作为映射中的值返回。 所以我创建了这个模板类: 并像这样使用它: IntelliSense提供了更多信息: 多个操作符“=”匹配这些操作数:function“valueorfunction::operator=(const std::function&other)[with T=std::wstring]”function“va

  • 我试图理解下面代码中的编译器错误。我有一个variadic模板函数,它接受具有指定类型的lambda,试图调用该函数会导致模板由于不匹配而不被视为有效的候选模板。 如果我将声明更改为不变: 然后它为上面的玩具示例工作,但对于真正的问题,我需要任意的论点。我是不是缺少了什么,或者还有什么方法可以做到这一点? 编辑:这被错误地标记为重复,我相信--受骗者没有回答我所问的问题。这个问题特别与这里的var