c++ 识别参数包中的第一个参数是否为与类型 T 分配兼容的指针

c++ recognise if the first parameter in a parameter pack is a pointer assign-compatible with type T

我最近才开始使用可变参数模板。

这是我的问题:

我有一个名为“addTo()”的函数,可以将新对象添加到集合中。对象的类型与函数所在的 class 的类型相同(它是一个模板 class)。 addTo() 也使用参数包来填充构造函数。 addTo 还收到地图(即集合)的密钥。现在集合使用 std::shared_ptr 存储对象。现在为了提高灵活性,我想添加将现有对象添加到集合中的功能,这样我也可以添加任何可分配的对象。

这里有一个例子(伪代码)

class A{
//whatever
~~some function that can be overloaded
A(int,float);
}
class B:public A{
//whatever
~~overloads that function
}
//In some other function
AddToClass<A> instance;
instance.addTo(key,12,2.2); //this is how it already works
instance.addTo(key, new B(12,3.5)); //this is how I also want it to work

我不知道这是否可以实现或如何实现,但是我恳请您详细解释(可能的)解决方案,因为我在理解参数包时仍然有很多问题。

我试过的

请向我详细解释如何执行此操作(如果可能)。这真的对我有很大帮助:)

---更多信息---

下面是 addToClass 的示例(伪代码,从我的脑海中写出来的):

template<class t>
class addToClass{
private:
    std::map<key, shared_ptr<t>> collection;'
    //sth else
public:
template<typename... Args>
void addTo(const Key &key, Args...args){
   collection.insert(std::pair<key, shared_ptr<t>>(key,std::make_shared<t>(std::forward<Args>(args)...));
}
//other stuff
}

现在一切正常,我想要的是“addTo()”也可以接受类型 t 的指针或指向从 [=19= 派生的某些 class 的指针].这将使我能够使该功能更加灵活,并在某些情况下节省我的工作量。

如果我没理解错的话,你的意图是 AddToClass<A>,而不是 AddToClass<int>

在这种情况下,我建议使用 emplace() 而不是 instert(),如下编写可变参数方法

  template <typename ... Args>
  void addTo (Key const & key, Args && ... args)
   { collection.emplace(key,
        std::make_shared<T>(std::forward<Args>(args)...)); }

并为(源自T)指针添加一个addTo()版本

  template <typename U>
  void addTo (Key const & key, U * p)
   { collection.emplace(std::piecewise_construct,
                        std::forward_as_tuple(key),
                        std::forward_as_tuple(p)); }

如果需要,您可以添加 std::enable_if 到 SFINAE,仅当 U 派生自 T.

时才启用最后一种方法

以下是完整的工作示例

#include <map>
#include <memory>

struct A
 { A (int, float) {} };

struct B: public A
 { B (int i, float f) : A{i, f} {} };

using Key = int;

template <typename T>
class addToClass
 {
   private:
      std::map<Key, std::shared_ptr<T>> collection;

   public:
      template <typename ... Args>
      void addTo (Key const & key, Args && ... args)
       { collection.emplace(key,
            std::make_shared<T>(std::forward<Args>(args)...)); }

      template <typename U>
      void addTo (Key const & key, U * p)
       { collection.emplace(std::piecewise_construct,
                            std::forward_as_tuple(key),
                            std::forward_as_tuple(p)); }
 };

int main ()
 {
   addToClass<A> instance;

   instance.addTo(1, 12,2.2);
   instance.addTo(2, new B(12,3.5));
 }

如果您还希望您的客户 class 可以指点,您需要 SFINAE 禁用您的附加 addTo 功能。

完整示例:

class X {};

class A
{
    public:
        A( int, double) {}
        A( X* ){}
};

class B: public A
{
    public:
        using A::A;
};

using Key = int;

template<class t>
class AddToClass
{   
    private:
        std::map<Key, std::shared_ptr<t>> collection;

    public:
        template<typename... Args>
            void addTo(const Key& key, Args...args)
            {
                collection.emplace( key, std::make_shared<t>(std::forward<Args>(args)...));
            }

        template < typename U, typename std::enable_if< std::is_base_of<t, U>::value, U>::type* = nullptr >
            void addTo( const Key &key, U* ptr, X* = 0 )
            {
                collection.emplace( key, ptr );
            }
};

int main()
{
    AddToClass<A> instance;
    Key key = 9;
    instance.addTo(key,12,2.2); //this is how it already works
    instance.addTo(key, new B{12,3.5}); //this is how I also want it to work
    instance.addTo(key, new A{ new X});
    instance.addTo(key, new B{ new X});
    instance.addTo(key, new X);
}