切换模板参数
switch over template parameters
当函数的模板参数的值仅在 运行 时已知时,必须编写考虑所有可能参数的代码,并相应地调用函数。
这个(过度)简化的例子说明了问题
#include <iostream>
template <int i>
void f()
{
std::cout << i << std::endl;
}
int main()
{
int i;
std::cin >> i;
if (i==0)
f<0>();
else if (i==1)
f<1>();
else if (i==2)
f<2>();
else
std::cout << "invalid input" << std::endl;
}
这显然非常乏味,尤其是在有很多可能值的情况下。更糟糕的是,如果模板参数大于 1,则需要考虑所有组合,例如:
#include <iostream>
template <int i, bool X>
void f()
{
std::cout << i << ' ';
if constexpr (X)
std::cout << "true" << std::endl;
else
std::cout << "false" << std::endl;
}
int main()
{
int i;
char c;
std::cin >> i;
std::cin >> c;
if (c == 'y')
{
if (i==0)
f<0,true>();
else if (i==1)
f<1,true>();
else if (i==2)
f<2,true>();
else
std::cout << "invalid input" << std::endl;
}
else
{
if (i==0)
f<0,false>();
else if (i==1)
f<1,false>();
else if (i==2)
f<2,false>();
else
std::cout << "invalid input" << std::endl;
}
}
(我当然知道滥用这个想法,即为所有模板组合实例化 f
,可能会导致代码膨胀。)
我正在寻找一个宏,它允许“基本上”用 i
和 x
一些 运行 时间变量编写等同于 f<i, x>()
的内容。
更具体地说,假设所有模板参数的值都是有限的,比如说
i = i1, i2, ... , in
x = x1, x2, ... , xn
我想要一个可以翻译类似这样内容的宏
CallF(f, i, {i1,...,in}, x, {x1,...,xn}, par...)
进入
if (i==i1)
{
if (x==x1)
f<i1,x1>(par...);
else if (x==x2)
f<i1,x2>(par...);
....
}
else if (i==i2)
{
if (x==x1)
f<i2,x1>(par...);
else if (x==x2)
f<i2,x2>(par...);
....
}
else if (i==i3)
....
这是一种针对 1 个模板参数执行此操作的方法:
#include <cstdio>
#include <stdexcept>
#include <utility>
template <int i>
void f(char const* s, bool b, double d) {
std::printf("%d -> %s %d %f\n", i, s, b, d);
}
template <class T, class ...Args>
[[noreturn]] void call_f(T&&, Args&&...) {
throw std::invalid_argument{"Argument not in the list"};
}
template <auto first, auto... rest, class T, class ...Args>
void call_f(T const& t, Args&&... args) {
if (t == first)
f<first>(std::forward<Args>(args)...);
else
call_f<rest...>(t, std::forward<Args>(args)...);
}
int main() {
int i = 2; // template argument
// other arguments for f
char const* s = "Hello";
bool b = false;
double d = 3.14;
// decide which one to call at run time.
call_f<1, 2, 3>(i, s, b, d);
}
当函数的模板参数的值仅在 运行 时已知时,必须编写考虑所有可能参数的代码,并相应地调用函数。
这个(过度)简化的例子说明了问题
#include <iostream>
template <int i>
void f()
{
std::cout << i << std::endl;
}
int main()
{
int i;
std::cin >> i;
if (i==0)
f<0>();
else if (i==1)
f<1>();
else if (i==2)
f<2>();
else
std::cout << "invalid input" << std::endl;
}
这显然非常乏味,尤其是在有很多可能值的情况下。更糟糕的是,如果模板参数大于 1,则需要考虑所有组合,例如:
#include <iostream>
template <int i, bool X>
void f()
{
std::cout << i << ' ';
if constexpr (X)
std::cout << "true" << std::endl;
else
std::cout << "false" << std::endl;
}
int main()
{
int i;
char c;
std::cin >> i;
std::cin >> c;
if (c == 'y')
{
if (i==0)
f<0,true>();
else if (i==1)
f<1,true>();
else if (i==2)
f<2,true>();
else
std::cout << "invalid input" << std::endl;
}
else
{
if (i==0)
f<0,false>();
else if (i==1)
f<1,false>();
else if (i==2)
f<2,false>();
else
std::cout << "invalid input" << std::endl;
}
}
(我当然知道滥用这个想法,即为所有模板组合实例化 f
,可能会导致代码膨胀。)
我正在寻找一个宏,它允许“基本上”用 i
和 x
一些 运行 时间变量编写等同于 f<i, x>()
的内容。
更具体地说,假设所有模板参数的值都是有限的,比如说
i = i1, i2, ... , in
x = x1, x2, ... , xn
我想要一个可以翻译类似这样内容的宏
CallF(f, i, {i1,...,in}, x, {x1,...,xn}, par...)
进入
if (i==i1)
{
if (x==x1)
f<i1,x1>(par...);
else if (x==x2)
f<i1,x2>(par...);
....
}
else if (i==i2)
{
if (x==x1)
f<i2,x1>(par...);
else if (x==x2)
f<i2,x2>(par...);
....
}
else if (i==i3)
....
这是一种针对 1 个模板参数执行此操作的方法:
#include <cstdio>
#include <stdexcept>
#include <utility>
template <int i>
void f(char const* s, bool b, double d) {
std::printf("%d -> %s %d %f\n", i, s, b, d);
}
template <class T, class ...Args>
[[noreturn]] void call_f(T&&, Args&&...) {
throw std::invalid_argument{"Argument not in the list"};
}
template <auto first, auto... rest, class T, class ...Args>
void call_f(T const& t, Args&&... args) {
if (t == first)
f<first>(std::forward<Args>(args)...);
else
call_f<rest...>(t, std::forward<Args>(args)...);
}
int main() {
int i = 2; // template argument
// other arguments for f
char const* s = "Hello";
bool b = false;
double d = 3.14;
// decide which one to call at run time.
call_f<1, 2, 3>(i, s, b, d);
}