微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

除了可变参数模板参数之外的输入参数未能编译

如何解决除了可变参数模板参数之外的输入参数未能编译

我努力一步一步地编写示例,使其清晰易懂。

此处显示的对象 BaseCreator 公开了一个创建函数,该函数使用内部类 NewObject 来分配类型为 T 的新对象。类 NewObject 方法是使用 new 运算符的常用方法,但可以使用专门化来更改它以使用不同的过程。我们稍后会看到。

template <typename F>
class BaseCreator
{
public:
    BaseCreator() = default;
    virtual ~BaseCreator() = default;

    // create function 
    template <typename T,typename... Args>
    std::shared_ptr<T> create(Args&&... parameters)
    {
        return std::shared_ptr<T>(NewObject<T,Args...>().get(std::forward<Args>(parameters)...));
    }

private:
    // creator object with default functionality to create a new object
    template <typename T,typename... Args>
    struct NewObject
    {
        T* get(Args&&... parameters)
        {
            return new T(std::forward<Args>(parameters)...);
        }
    };
};

这很好用,例如假设我们有以下对象类型:

struct A
{
    A(int i_i,const std::string& i_s) : i(i_i),s(i_s) {}
    void addVal(int i_i) { i+=i_i; }
    int i = 0;
    std::string s;
};

struct B
{
    B(const std::vector<float>& i_v) : v(i_v) {}
    void addVal(int i_i) { v.push_back((float)i_i); }
    std::vector<float> v;
};

我们可以轻松创建它们,例如:

// declare type for a creator identity 
struct Group111 {};

// creator object
BaseCreator<Group111> cCreator111;

// creating A and B
std::shared_ptr<A> spA = cCreator111.create<A>(5,"Hello");
std::shared_ptr<B> spB = cCreator111.create<B>(std::vector<float>({ 0.5f,0.1f,0.7f,0.9f }));

我们还可以为特定对象和特定类型的创建者声明特定的创建方法。例如,使用 Group222 的创建者创建对象 A 的特化示例:

// declare type for a creator identity 
struct Group222 {};

// specialize NewObject for BaseCreator<Group222> for creating A
template<> 
template< typename... Args> 
struct BaseCreator<Group222>::NewObject<A,Args...>
{
    A* get(int i_factor,int i_i,const std::string& i_s)
    {
        A* p = new A(i_i,i_s);
        p->i *= i_factor;
        return p;
    }
};

使用 Group222 类型的创建者创建对象 A 的方法方法不同。

// creator object
BaseCreator<Group222> cCreator222;

// creating A with creator of Group222 needs Now additional input argument 
std::shared_ptr<A> spA = cCreator222.create<A>(3,5,"Hello");

// creating A with creator of Group222 is the same as creating using creator cCreator111
std::shared_ptr<B> spB = cCreator222.create<B>(std::vector<float>({ 0.5f,0.9f }));

现在的问题:)

现在,我想派生一个新的 BaseCreator 来拥有以下一个,如您所见,它具有代理创建函数,并使用额外的整数调用其基类 1:

class Creator333 : public BaseCreator<Creator333>
{
public:
    Creator333() = default;
    virtual ~Creator333() = default;

    // creator
    template <typename T,typename... Args>
    std::shared_ptr<T> create(Args&&... parameters)
    {
        int adder = 5; // just for the example
        return std::shared_ptr<T>(BaseCreator<Creator333>::create<T>(adder,std::forward<Args>(parameters)...));
    }

};

它带有专门的 BaseCreator<Creator333>::NewObject,它应该为任何对象处理这个额外的整数(在这个例子中 - 假设对象有一个名为 addVal() 的成员函数

template<> 
template<typename T,typename... Args> 
struct BaseCreator<Creator333>::NewObject<T,Args...>
{
    T* get(int i_adder,Args&&... parameters)
    {
        T* p = new T(std::forward<Args>(parameters)...);
        p->addVal(i_adder);
        return p;
    }
};

如果我要尝试创建一个对象,假设 B 使用这个 Creator333:

Creator333 cCreator333;

// creation of B using Creator333 
std::shared_ptr<B> spB3 = cCreator333.create<B>(std::vector<float>({ 0.1f,0.2f}));

我会得到一个编译器错误

error C2660: 'BaseCreator<Creator333>::NewObject<T,int &,_Ty>::get': function does not take 2 arguments
1>        with
1>        [
1>            T=B,1>            _Ty=std::vector<float,std::allocator<float>>
1>        ]

但这很奇怪,因为函数确实应该得到如下两个参数:

  1. Create333::create - 得到一个包含一个元素的包 std::vector({ 0.1f,0.2f})

  2. 它用额外的整数调用它的基类 BaseCreator<Create333>::create,因此 BaseCreator<Create333>::create 得到一个包含两个元素的包:int(5) 和 std::vector({ 0.1f,0.2f})

  3. BaseCreator<Create333>::create`` calls BaseCreator::NewObject.get``` 其中包的第一个元素用于 get(adder),包的另一个元素用于 get(Args ...

那么问题是什么以及如何解决

谢谢

解决方法

以下是解决方案但不是答案, 这意味着代码有效,但我不明白为什么这项工作和问题中的那个没有。因此,如果有人可以描述原因,我相信这将有助于许多人更深入地了解该主题。

感谢@Kuba 的评论,我根据他建议的词进行了搜索,并在此 stackoverflow question 中找到了一个代码,这激发了我的以下解决方案:

我为 Helper 添加了一个 Creator333 类,如下所示。它有助于将输入包拆分为所需的两部分:附加整数和来自应用程序代码的原始包。但我也不得不将特殊的创建代码移入其中。

class Creator333 : public BaseCreator<Creator333>
{
public:
    Creator333() = default;
    virtual ~Creator333() = default;

    // creator
    template <typename T,typename... Args>
    std::shared_ptr<T> create(Args&&... parameters)
    {
        int adder = 5; // just for the example
        return std::shared_ptr<T>(BaseCreator<Creator333>::create<T>(adder,std::forward<Args>(parameters)...));
    }

    // helper class for splitting given pack into  desired two parts: 
    // the additional integer and the original pack came from the application code
    template<typename T,typename FirstTypeT,typename... Args>
    struct Helper
    {
        T* get(FirstTypeT i_adder,Args&&... parameters)
        {
            T* p = new T(std::forward<Args>(parameters)...);
            p->addVal(i_adder);
            return p;
        }
    };
};

特化 BaseCreator<Creator333>::NewObject 本身现在只需要使用 Helper,如下所示:

template<> 
template<typename T,typename... Args>
struct BaseCreator<Creator333>::NewObject<T,Args...>
{
    T* get(Args&&... parameters)
    {
        return Creator333::Helper<T,Args... >().get(std::forward<Args>(parameters)...);
    }
};

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。