C++ 单个c+上的抽象+;对象和std::使用模板的对象对
假设以下模板构造:C++ 单个c+上的抽象+;对象和std::使用模板的对象对,c++,c++11,abstraction,C++,C++11,Abstraction,假设以下模板构造: enum class ENUM {SINGLE, PAIR}; // General data type template<ENUM T, class U>class Data; // Partially specialized for single objects template<class U>Data<ENUM::SINGLE, U> : public U { // Forward Constructors, ... }; //
enum class ENUM {SINGLE, PAIR};
// General data type
template<ENUM T, class U>class Data;
// Partially specialized for single objects
template<class U>Data<ENUM::SINGLE, U> : public U {
// Forward Constructors, ...
};
// Partially specialized for pairs of objects
template<class U>Data<ENUM::PAIR, U> : public std::pair<U,U> {
// Forward Constructors, ...
};
但我必须对许多方法和运算符以及许多不同类型的方法和运算符执行此操作,尽管这些方法和运算符都类似于此示例
解决方案的语法可能与我上面写的非常不同,这只是为了演示我想要实现的目标。我更喜欢没有宏的解决方案,但也可以接受
这样的抽象可以在C++11中实现吗
我想这样做的原因是
ENUM::Single
和ENUM::PAIR
,因为专门化之间的所有差异都将数学化上述模式(避免大量代码重复)您可以向类中添加一个公共方法
template<class U>
Data<ENUM::SINGLE, U> : public U {
// Forward Constructors, ...
void handle() {
//do some specific handling for this type
return;
}
};
模板
资料来源:美国公共图书馆{
//正向构造函数。。。
无效句柄(){
//对这种类型做一些特定的处理
返回;
}
};
现在someMethod将只调用正确的“句柄”,它将自动在两者之间切换
template<typename T>
someMethod(T& data) {
data.handle();
}
//If you want to bind your function to some other name, you could
//create a functor that calls someMethod with the arguments passed in _1
//I haven't tested it, there might be some syntax problems with the way you pass in the function name
auto someOtherMethod = std::bind (someMethod, _1);
模板
方法(T&data){
data.handle();
}
//如果要将函数绑定到其他名称,可以
//创建一个函子,用传入的参数调用someMethod _1
//我还没有测试过,传入函数名的方式可能存在一些语法问题
autosomeothermethod=std::bind(someMethod,_1);
如果您的类型没有实现handle方法,则将出现严重的编译错误。如果您希望提供默认实现并避免编译错误,则有一个名为SFINAE(替换失败不是错误)的常见模式正好可以做到这一点。您可以尝试创建一个模板方法
applyMethod
。这是一个完整的例子。我使用了一个只包含一个静态方法的Executor
类,因为我找不到更好的方法来处理使用任何类型参数的方法
#include <iostream>
#include <string>
enum ENUM {SINGLE, PAIR};
// General data type
template<ENUM T, class U>class Data {
};
// Partially specialized for single objects
template<class U>
class UData : public Data<ENUM::SINGLE, U>, public U {
// Forward Constructors, ...
public:
UData(const U& u): U(u) {};
};
// Partially specialized for pairs of objects
template<class U>
class PData : public Data<ENUM::PAIR, U>, public std::pair<U,U> {
// Forward Constructors, ...
public:
PData(const U& u1, const U& u2): std::pair<U, U>(u1, u2) {};
};
template <class U, typename... P>
class Executor {
Executor() = delete;
public:
template<void (U::*M)(P... params)>
static void applyMethod(Data<ENUM::SINGLE, U> &data, P ...params) {
UData<U>& ud= reinterpret_cast<UData<U>& >(data);
U& u = static_cast<U&>(ud);
(u.*M)(params...);
}
template<void (U::*M)(P... params)>
static void applyMethod(Data<ENUM::PAIR, U> &data, P ...params) {
PData<U>& pd = reinterpret_cast<PData<U>& >(data);
(pd.first.*M)(params...);
(pd.second.*M)(params...);
}
};
class X {
std::string name;
public:
X(const std::string& name): name(name) { };
void doStuff(void) {
std::cout << "DoStuff : " << name << std::endl;
}
void doStuff(int i) {
std::cout << "DoStuff : " << name << " - " << i << std::endl;
}
};
int main() {
X x1("x1");
X x2("x2");
X x3("x3");
UData<X> data1(x1);
PData<X> data2(x2, x3);
Executor<X>::applyMethod<&X::doStuff>(data1);
Executor<X, int>::applyMethod<&X::doStuff>(data2, 12);
return 0;
}
#包括
#包括
枚举枚举{单个,对};
//一般数据类型
模板类数据{
};
//部分专用于单个对象
模板
UData类:公共数据、公共U{
//正向构造函数。。。
公众:
乌达塔(常量U&U):U(U){};
};
//部分专用于成对对象
模板
类PData:公共数据,公共std::pair{
//正向构造函数。。。
公众:
PData(常数U和u1,常数U和u2):std::pair(u1,u2){};
};
模板
类执行器{
Executor()=删除;
公众:
模板
静态无效应用方法(数据和数据、P…参数){
UData&ud=重新解释铸件(数据);
U&U=静态铸件(ud);
(u.*M)(参数…);
}
模板
静态无效应用方法(数据和数据、P…参数){
PData&pd=重新解释铸件(数据);
(pd.first.*M)(参数…);
(pd.second.*M)(参数…);
}
};
X类{
std::字符串名;
公众:
X(const std::string&name):name(name){};
空隙度凝灰岩(空隙){
std::cout这里有一个替代Serge Ballesta的解决方案,使用lambdas
#include <functional>
template<ENUM T, class U>void for_single_or_pair(
Data<T, U>& data,
std::function<void(U&)> function);
template<class U>void for_single_or_pair(
Data<ENUM::SINGLE, U>& data,
std::function<void(U&)> function) {
function(data);
}
template<class U>void for_single_or_pair(
Data<ENUM::PAIR, U>& data,
std::function<void(U&)> function) {
function(data.first);
function(data.second);
}
#包括
单个\u或\u对的templatevoid(
数据与数据,
std::函数;
单个\u或\u对的templatevoid(
数据与数据,
std::函数(函数){
功能(数据);
}
单个\u或\u对的templatevoid(
数据与数据,
std::函数(函数){
功能(数据优先);
功能(数据第二);
}
用法:
template<ENUM T>someMethod(Data<T, SomeClass> data) {
for_single_or_pair(data,[](SomeClass& someObject) {
// Play around with someObject in any way
});
}
templatesomeMethod(数据){
对于单个或成对(数据,[](SomeClass和someObject){
//以任何方式玩弄某个物体
});
}
通过这种方式,除了使用SomeClass的成员方法外,还可以以任何其他方式使用数据
我很乐意听取对此解决方案的评论(如果可以推广到在for_single_或_pair方法中使用多个数据)。这并不是我想要实现的目标(请参见我的编辑)。然后你可以做的是使用自定义方法而不是运算符++。让我编辑我的答案。我注意到我的问题不够精确。因此,很遗憾,你更新的答案仍然不是我想要的(请参阅我的编辑2)。检查我的编辑!不过我可以说,如果你有几个名称不同的方法,所有方法都在做同一件事,那么就有一个设计问题。可能是你被束缚在一个传统的API上,你无法触及。这是另一个故事:-)如果你需要在不同类型之间切换,你总是必须提供一个专门化,因此你将必须在某个地方编写一个方法来处理这种情况。如果您只想从不同类型调用相同的方法,那么您可以使用模板化的friend函数。或者您可以使用traits类在不同类型之间切换。我刚刚注意到您创建了类UData
和PData
,因此我无法直接工作尤其是使用数据数据
,即我无法调用Executor::applyMethod(数据)
,除非T
实际上已经在代码中确定。所以我仍然无法避免someMethod
的专门化,可以吗?@user2296653:可以!我刚刚找到了一种方法,其中Executor
类是唯一的,并根据传递给它的实际数据使用正确的方法。
#include <iostream>
#include <string>
enum ENUM {SINGLE, PAIR};
// General data type
template<ENUM T, class U>class Data {
};
// Partially specialized for single objects
template<class U>
class UData : public Data<ENUM::SINGLE, U>, public U {
// Forward Constructors, ...
public:
UData(const U& u): U(u) {};
};
// Partially specialized for pairs of objects
template<class U>
class PData : public Data<ENUM::PAIR, U>, public std::pair<U,U> {
// Forward Constructors, ...
public:
PData(const U& u1, const U& u2): std::pair<U, U>(u1, u2) {};
};
template <class U, typename... P>
class Executor {
Executor() = delete;
public:
template<void (U::*M)(P... params)>
static void applyMethod(Data<ENUM::SINGLE, U> &data, P ...params) {
UData<U>& ud= reinterpret_cast<UData<U>& >(data);
U& u = static_cast<U&>(ud);
(u.*M)(params...);
}
template<void (U::*M)(P... params)>
static void applyMethod(Data<ENUM::PAIR, U> &data, P ...params) {
PData<U>& pd = reinterpret_cast<PData<U>& >(data);
(pd.first.*M)(params...);
(pd.second.*M)(params...);
}
};
class X {
std::string name;
public:
X(const std::string& name): name(name) { };
void doStuff(void) {
std::cout << "DoStuff : " << name << std::endl;
}
void doStuff(int i) {
std::cout << "DoStuff : " << name << " - " << i << std::endl;
}
};
int main() {
X x1("x1");
X x2("x2");
X x3("x3");
UData<X> data1(x1);
PData<X> data2(x2, x3);
Executor<X>::applyMethod<&X::doStuff>(data1);
Executor<X, int>::applyMethod<&X::doStuff>(data2, 12);
return 0;
}
#include <functional>
template<ENUM T, class U>void for_single_or_pair(
Data<T, U>& data,
std::function<void(U&)> function);
template<class U>void for_single_or_pair(
Data<ENUM::SINGLE, U>& data,
std::function<void(U&)> function) {
function(data);
}
template<class U>void for_single_or_pair(
Data<ENUM::PAIR, U>& data,
std::function<void(U&)> function) {
function(data.first);
function(data.second);
}
template<ENUM T>someMethod(Data<T, SomeClass> data) {
for_single_or_pair(data,[](SomeClass& someObject) {
// Play around with someObject in any way
});
}