模板化函数范围内的条件模板化类型别名

Conditional templated type aliases in scope of templated function

本文关键字:类型 别名 条件 范围内 函数      更新时间:2023-10-16

假设我有N函数,它们有一组相同的参数。 我调用带有参数的工厂方法,以及一些允许我在N函数之间进行选择的值。

一种不整洁的方法是像这样做一个 if 语句:

if(choice == 1)
foo_one<T>(args);
else if (choice == 2)
foo_two<T>(args);
etc

这很好,除了在我的情况下,参数数量很大。 因此,工厂方法非常拥挤。

假设我有一个调用工厂方法的主函数:

int main(int argc, char *argv[])
{
int choice = 1;
float arg = 1.5;
foo_choose(choice, arg);
return 0;
}

我正在考虑对choice参数进行分支,并在其中设置函数别名的 if 语句。

这意味着我只需要通过一次我的论点,无论N有多大。

它可能看起来像这样:

template <typename T>
void foo_one(T arg) { std::cout << "foo_onen"; };
template <typename T>
void foo_two(T arg) { std::cout << "foo_onen"; };
template <typename T>
void foo_choose(int choice, T arg)
{
if(choice == 1)
using foo = foo_one<T>;
else
using foo = foo_two<T>;        
foo(arg);
};

但是,我无法让它与模板一起使用。 我是否缺少明显的东西,或者我应该添加的搜索词。

由于我可能会多次调用foo_choosechoice使用不同的值,因此我不希望别名foo存在于函数范围之外。

这个问题表明我可能走错了路,但我不确定。

问题

template <typename T>
void foo_choose(int choice, T arg)
{
if(choice == 1)
using foo = foo_one<T>;
else
using foo = foo_two<T>;        
foo(arg);
};

是 using 语句是作用域语句。 这意味着它们仅适用于声明的范围,因此一旦您进入foo(arg);foo超出范围并且您会收到错误。 您可以获取指向函数的指针,而不是获取函数的别名,然后在末尾调用指针。 那嘟嘟看起来像

template <typename T>
void foo_choose(int choice, T arg)
{
using f_ptr = void(*)(T);
f_ptr foo;
if(choice == 1)
foo = foo_one<T>;
else
foo = foo_two<T>;        
foo(arg);
};

这确实伴随着必须指定所有函数模板参数的警告。

如果所有候选项都是同一类型的函数,则只需设置一个函数指针的本地数组并从中进行选择:

template <typename T>
void foo_choose(int choice, T arg)
{
constexpr void (*funcs[])(T) = { foo_one<T>, foo_two<T> };
assert(choice > 0 && choice < std::extent_v<decltype(funcs)>);
return funcs[choice](arg);
};

现场示例在这里

这里的其他答案已经解释了为什么你原来的方法不起作用。我想我不能补充一下...

次要点

无需使用

using foo = foo_one<T>;

其次

foo(arg);

你不妨使用

foo_one(arg);

更重要

正如您已经注意到的,使用级联if/else语句是一个维护问题,很容易导致错误。

如果您可以保留可用于调度对相应函数的调用的函数/函子映射,那就更好了。但是,对于函数模板,我认为没有明确的通用类型可用于创建函数/函子映射。

让我们回家,其他人有正确的想法来证明这是可以做到的。