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
我不知道这是否可以实现或如何实现,但是我恳请您详细解释(可能的)解决方案,因为我在理解参数包时仍然有很多问题。
我试过的
- 我尝试使用动态转换,但我没能做到,所以
参数包得到扩展(因为我真的不知道如何使用
它们除了非常基本的功能转发之外)
- 我试着把它放在
std::make_shared
调用(构造函数)中,但这不起作用,因为我不想强制类型为每个派生的 class 都有一个构造函数(似乎违反直觉和不良做法)
请向我详细解释如何执行此操作(如果可能)。这真的对我有很大帮助:)
---更多信息---
下面是 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);
}
我最近才开始使用可变参数模板。
这是我的问题:
我有一个名为“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
我不知道这是否可以实现或如何实现,但是我恳请您详细解释(可能的)解决方案,因为我在理解参数包时仍然有很多问题。
我试过的
- 我尝试使用动态转换,但我没能做到,所以 参数包得到扩展(因为我真的不知道如何使用 它们除了非常基本的功能转发之外)
- 我试着把它放在
std::make_shared
调用(构造函数)中,但这不起作用,因为我不想强制类型为每个派生的 class 都有一个构造函数(似乎违反直觉和不良做法)
请向我详细解释如何执行此操作(如果可能)。这真的对我有很大帮助:)
---更多信息---
下面是 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);
}