这是我昨天做的this post的后续,它完美地回答了我的问题,但是我意识到我的问题比我最初问的要复杂一些。
比如,我有以下代码:
#include <iostream>
#include <typeinfo>
#include <ratio>
#include <vector>
#include <memory>
struct IStrategy
{
virtual void Declare() = 0;
virtual void Build() = 0;
};
template<typename T>
struct IStrategyStorer : public IStrategy
{
using StoredType=T;
T& stored;
IStrategyStorer(T& i_Input):
stored{i_Input}
{}
};
template<typename T>
struct BasicStrategy : public IStrategyStorer<T>
{
BasicStrategy(T& i_Input):
IStrategyStorer<T>(i_Input)
{
}
void Declare()
{
std::cout << "Declaring type : " << typeid(T).name() << " as parameter (Basic Strategy)" << std::endl;
IStrategyStorer<T>::stored = 0;
}
void Build()
{
std::cout << "Building type (Basic Strategy) : " << typeid(T).name() << std::endl;
IStrategyStorer<T>::stored = 1;
}
};
template<typename RATIO, typename T>
struct ImposedValueStrategy : public IStrategyStorer<T>
{
ImposedValueStrategy(T& i_Input):
IStrategyStorer<T>(i_Input)
{
}
void Declare()
{
std::cout << "Declaring type : " << typeid(T).name() << " as parameter (ImposedValue Strategy)" << std::endl;
IStrategyStorer<T>::stored = 0;
}
void Build()
{
std::cout << "Building type (ImposedValue Strategy): " << typeid(T).name() << std::endl;
IStrategyStorer<T>::stored = ((double) RATIO::num) / ((double) RATIO::den);
}
};
template<typename Ratio, typename PARENT_STRATEGY>
struct RatioStrategy : public PARENT_STRATEGY
{
using Type = typename PARENT_STRATEGY::StoredType;
RatioStrategy(Type& i_Input):
PARENT_STRATEGY(i_Input)
{
}
void Declare()
{
std::cout << "Transfering type declaration (currently in RatioStrategy)" << std::endl;
PARENT_STRATEGY::Declare();
}
void Build()
{
PARENT_STRATEGY::Build();
std::cout << "Applying ratio multiplication" << std::endl;
PARENT_STRATEGY::stored *= ((double)Ratio::num)/((double)Ratio::den);
}
};
template<typename Ratio, typename PARENT_STRATEGY>
struct SumStrategy : public PARENT_STRATEGY
{
using Type = typename PARENT_STRATEGY::StoredType;
SumStrategy(Type& i_Input):
PARENT_STRATEGY(i_Input)
{
}
void Declare()
{
std::cout << "Transfering type declaration (currently in SumStrategy)" << std::endl;
PARENT_STRATEGY::Declare();
}
void Build()
{
PARENT_STRATEGY::Build();
std::cout << "Applying ratio sum" << std::endl;
PARENT_STRATEGY::stored += ((double)Ratio::num)/((double)Ratio::den);
}
};
template<typename Ratio1, typename Ratio2, typename PARENT_STRATEGY>
struct AffineStrategy : public PARENT_STRATEGY
{
using Type = typename PARENT_STRATEGY::StoredType;
AffineStrategy(Type& i_Input):
PARENT_STRATEGY(i_Input)
{
}
void Declare()
{
std::cout << "Transfering type declaration (currently in AffineStrategy)" << std::endl;
PARENT_STRATEGY::Declare();
}
void Build()
{
PARENT_STRATEGY::Build();
std::cout << "Applying affine transformation" << std::endl;
PARENT_STRATEGY::stored = PARENT_STRATEGY::stored * ((double)Ratio1::num)/((double)Ratio1::den) + ((double)Ratio2::num)/((double)Ratio2::den);
}
};
std::vector<IStrategy*> StrategiesList{}; // This stores the strategies for delayed building!
void buildStrategies()
{
for(auto& strat : StrategiesList)
{
strat -> Build();
}
}
template<template<typename> class Strategy = BasicStrategy, typename T>
void generic_parameter(T& i_Data)
{
Strategy<T>* strat = new Strategy<T>(i_Data);
StrategiesList.push_back((IStrategy*)strat);
strat->Declare();
}
template<class Strategy, typename T>
void generic_parameter(T& i_Data)
{
Strategy* strat = new Strategy(i_Data);
StrategiesList.push_back((IStrategy*)strat);
strat->Declare();
}
int main()
{
double d = 24;
generic_parameter(d);
generic_parameter<ImposedValueStrategy<std::ratio<4,3>, double>>(d);
generic_parameter<RatioStrategy<std::ratio<2,1>, SumStrategy<std::ratio<3,1>, BasicStrategy<double>>>>(d);
generic_parameter<AffineStrategy<std::ratio<2, 1>, std::ratio<5, 1>, BasicStrategy<double>>>(d);
buildStrategies();
std::cout << d << std::endl;
return 0;
}
在generic_parameter
的第一个重载中使用的template参数允许我定义一个BasicStrategy
,而不必指定两次类型(在本例中是int
或double
)。
然而,我找不到一种方法来使用相同的原则来推导非违约策略的这种类型,无论是:
1.堆叠策略。例如:* 基本策略&乘以比率 *
1.需要比类型更多的模板参数的更复杂的策略。例如:* 强制价值战略 *
我希望我能在'main()~函数中写的是:
generic_parameter(d); // Uses BasicStrategy : currently works!
generic_parameter<ImposedValueStrategy<std::ratio<4,3>>>(d); // This does not compile
generic_parameter<AffineStrategy<std::ratio<2, 1>, std::ratio<5, 1>, BasicStrategy>>(d); // This does not compile
generic_parameter<RatioStrategy<std::ratio<2,1>, SumStrategy<std::ratio<3,1>, ImposedValueStrategy<std::ratio<3,1>>>>>(d); // This would not compile either
上下文:
我正在一个遗留API(用C & Fortran编写)之上构建一个C11接口,它使用户能够声明所谓的"参数"。API然后存储指向这些参数的指针,然后稍后这些变量将由API填充值。
这对于算术变量和C风格数组非常有效,但现在需求已经改变,C API必须能够将任何对象声明为参数,因此每个对象都需要一个"策略",描述对象的哪一部分必须向API声明,以及必须如何构建对象,用户可以定义自己的"策略"。
请注意,由于API在声明后会延迟获取数据,因此每个策略都必须拥有对用户数据的引用,以便在数据准备就绪时构建它。此外,还需要能够将策略"堆叠"在彼此的顶部,因为这样可以避免使用临时变量(特别是对于单位转换,这会导致大量错误)。
1条答案
按热度按时间ozxc1zmp1#
在你的另一个问题中,你已经知道了模板的模板参数。你只是缺少了一个步骤。
假设您有一个类模板
现在你想绑定参数
A
,然后推导出B
,如果你有一个只带一个参数B
的模板,这就可以了,所以我们可以把它重写为:在代码中应用这个方法并引入模板tempalte参数,结果如下(我删除了一些策略,只保留了一些):
Live Demo
语法有点笨拙,但我希望总体思路能够清晰,不是提供所有参数并示例化类型,而是只示例化一个 Package 器,并且
T
的推导保留到“以后”调用generic_parameter
时。我建议使用变量模板而不是继承树。
其中
get
从源中检索值并应用所有transformations
。这将避免需要如此深的嵌套,而在需要时嵌套仍然是可能的。