我正在寻找另一种c ++模式来实现这个目标:
从文件中的选项中读取(假设它是A或B)。 在一个循环中,我想根据选项重复调用模板函数,但我不想每次检查值,相反,我希望编译器生成两种可能性,并选择具有模板A的那个,如果选项设置为A,如果选项设置为B,则使用模板B.
如果我这样做:
Option option = readFromFile("AorB");
for(int i = 0; i < 100000; ++i)
{
performOperation<option>(); // Long but fast function I don't want to define twice
}
我收到以下错误:
error: the value of 'option' is not usable in a constant expression
如何实现理想的行为?
答案 0 :(得分:2)
为了使代码更奇怪,更多元;)你可以使用可变参数模板,lambdas和constexpr隐式转换:
#include <iostream>
template <char C>
struct Option {
constexpr operator char() {
return C;
}
};
template <char Opt>
void performOperation() {
std::cout << Opt << std::endl;
}
template <char... Options>
void runOption() {
char optionFromFile = 'a';
int dummy[] = {([](auto option, char chosen) {
if (chosen == option) {
for(int i = 0; i < 5; ++i) {
performOperation<option>();
}
}
}(Option<Options>{}, optionFromFile), 0)...};
static_cast<void>(dummy);
}
int main() {
runOption<'a', 'b'>();
}
玩得开心!
答案 1 :(得分:1)
正如其他人所提到的,你不能将变量传递给需要编译时常量的东西。
如果你有一个“A”或“B”的东西而且你每次都担心检查它,那么你可以自己扩展循环/条件:
Option option = readFromFile("AorB");
if(option.isA())
{
for(int i = 0; i < 100000; ++i)
{
performOperationA();
}
else
{
for(int i = 0; i < 100000; ++i)
{
performOperationB();
}
}
答案 2 :(得分:1)
如果希望operation
在运行时选择行为,那么您可能希望创建一个类来封装变化的行为。接下来,根据选项值A或B创建一个类的实例。然后在循环内部,将类实例传递给operation
。
我在下面提供了一个在类层次结构中实现OptionA和OptionB的示例。如果你这样做,那么你甚至根本不需要模板。但是你没有详细说明你的操作行为如何变化,所以我不想过多地考虑你必须使用的东西。只有当您有两个实现相同接口的不相关类时,才需要该模板。
#include <iostream>
#include <string>
class OptionType {
public: virtual int calculate( int x ) = 0;
};
class OptionA :public OptionType {
public: int calculate( int x ) { return x+99; }
};
class OptionB : public OptionType {
public: int calculate( int x ) { return x*100; }
};
template<class T>
void performOperation( T& option, int x ) {
// your performOperation is a long function
// this one is short but shows how the behavior can vary by option
std::cout << option.calculate( x ) << std::endl;
}
int main( int argc, char* argv[] )
{
// Option option = readFromFile("AorB");
// pass A or B from the command line
char option = (argc > 1) ? argv[1][0] : 'A'; // your code reads this from a file
OptionType* optionObject;
if( option == 'A' ) optionObject = new OptionA();
else optionObject = new OptionB();
for(int i = 0; i < 10; ++i)
{
performOperation( *optionObject, i );
}
}
答案 3 :(得分:0)
你不能,因为选项是变量,模板是编译时间。 performOperation需要在&lt;&gt;上接收一个常量值。 并且由于操作在运行时出现 - 您需要if。
但你可以使用分支预测做更少的工作 - 如果你在传递给/ if调用(值)其他call_2(值)之前对向量进行排序,它会运行得更快。
答案 4 :(得分:0)
模板参数必须在编译时知道。在运行时,实例化模板的新实例为时已晚。您需要强制生成运行时可能需要的每个实例,并实现某种形式的调度。最简单的方法是使用交换机进行调度功能。例如:
enum class Option {
Opt1,
Opt2,
Opt3
};
template<Option opt>
void Operation() {}
void performOperation(const Option opt)
{
switch (opt)
{
case(Option::Opt1):
Operation<Option::Opt1>();
break;
case(Option::Opt2):
Operation<Option::Opt2>();
break;
case(Option::Opt3):
Operation<Option::Opt3>();
break;
default:
// Handle however you want
}
}
另一种解决方案是使用std::function
:
#include <map>
#include <functional>
enum class Option {
Opt1,
Opt2,
Opt3
};
template<Option opt>
void Operation() {}
const std::map<Option, std::function<void()>> func_map = {
{ Option::Opt1, []{Operation<Option::Opt1>(); }},
{ Option::Opt2, []{Operation<Option::Opt2>(); }},
{ Option::Opt3, []{Operation<Option::Opt3>(); }}
};
void performOperation(const Option opt)
{
func_map.at(opt)();
}
答案 5 :(得分:-1)
如果我正确理解了这个问题。 你可以这样试试:
for(int i = 0; i&lt; 100000; ++ i) {
#ifdef A
read("A");
#endif
#ifdef B
read("B");
#endif
}
在编译器级别,您可以选择: g ++ main.cpp -D A. 要么 g ++ main.cpp -D B