您可以使用(可能是附加的)模板参数来增强您的算法,如下所示:
enum class algorithm_type
{
type_a,
type_b,
type_c
};
template <algorithm_type AlgorithmType>
void foo(int usual, double args)
{
std::cout << "common code" << std::endl;
if (AlgorithmType == algorithm_type::type_a)
{
std::cout << "doing type a..." << usual << ", " << args << std::endl;
}
else if (AlgorithmType == algorithm_type::type_b)
{
std::cout << "doing type b..." << usual << ", " << args << std::endl;
}
else if (AlgorithmType == algorithm_type::type_c)
{
std::cout << "doing type c..." << usual << ", " << args << std::endl;
}
std::cout << "more common code" << std::endl;
}
现在您可以通过此模板参数选择您的行为:
foo<algorithm_type::type_a>(11, 0.1605);
foo<algorithm_type::type_b>(11, 0.1605);
foo<algorithm_type::type_c>(11, 0.1605);
该类型是一个常量表达式,产生一个编译时决定的分支(即,其他已知为死代码并被删除)。事实上,你的编译器应该警告你这一点(你如何处理这取决于你)。
但是您仍然可以很好地发送运行时值:
#include <stdexcept>
void foo_with_runtime_switch(algorithm_type algorithmType,
int usual, double args)
{
switch (algorithmType)
{
case algorithm_type::type_a:
return foo<algorithm_type::type_a>(usual, args);
case algorithm_type::type_b:
return foo<algorithm_type::type_b>(usual, args);
case algorithm_type::type_c:
return foo<algorithm_type::type_c>(usual, args);
default:
throw std::runtime_error("wat");
}
}
foo_with_runtime_switch(algorithm_type::type_a, 11, 0.1605);
foo_with_runtime_switch(algorithm_type::type_b, 11, 0.1605);
foo_with_runtime_switch(algorithm_type::type_c, 11, 0.1605);
算法的内部结构保持不变(消除了死分支,相同的优化),只是你到达那里的方式发生了变化。(请注意,可以概括枚举的想法,以便自动生成此开关;如果您发现自己有很多变体,这可能会很好学。)
当然,您仍然可以#define
将特定算法作为默认算法:
#define FOO_ALGORITHM algorithm_type::type_a
void foo_with_define(int usual, double args)
{
return foo<FOO_ALGORITHM>(usual, args);
}
foo_with_define(11, 0.1605);
所有这些一起为您提供了这三个方面的优势,无需重复。
在实践中,您可以将所有三个作为重载:一个用于知道在编译时使用哪种算法的用户,需要在运行时选择它的用户,以及只需要默认值的用户(您可以通过项目覆盖它-宽#define
):
// foo.hpp
enum class algorithm_type
{
type_a,
type_b,
type_c
};
// for those who know which algorithm to use
template <algorithm_type AlgorithmType>
void foo(int usual, double args)
{
std::cout << "common code" << std::endl;
if (AlgorithmType == algorithm_type::type_a)
{
std::cout << "doing type a..." << usual << ", " << args << std::endl;
}
else if (AlgorithmType == algorithm_type::type_b)
{
std::cout << "doing type b..." << usual << ", " << args << std::endl;
}
else if (AlgorithmType == algorithm_type::type_c)
{
std::cout << "doing type c..." << usual << ", " << args << std::endl;
}
std::cout << "more common code" << std::endl;
}
// for those who will know at runtime
void foo(algorithm_type algorithmType, int usual, double args)
{
switch (algorithmType)
{
case algorithm_type::type_a:
return foo<algorithm_type::type_a>(usual, args);
case algorithm_type::type_b:
return foo<algorithm_type::type_b>(usual, args);
case algorithm_type::type_c:
return foo<algorithm_type::type_c>(usual, args);
default:
throw std::runtime_error("wat");
}
}
#ifndef FOO_ALGORITHM
// chosen to be the best default by profiling
#define FOO_ALGORITHM algorithm_type::type_b
#endif
// for those who just want a good default
void foo(int usual, double args)
{
return foo<FOO_ALGORITHM>(usual, args);
}
当然,如果某些实现类型总是比其他实现类型更差,那就去掉它。但是,如果您发现有两个有用的实现,那么以这种方式保留两者并没有什么坏处。