【问题标题】:Generate code instantiating a function template with different arguments生成使用不同参数实例化函数模板的代码
【发布时间】:2017-11-25 08:10:42
【问题描述】:

给定以下代码:

#include <iostream>

template <int X, int Y>
int foo(int v) // dummy parameter
{
    return v * X + v / Y; // dummy calculation
}

int main()
{
    // x, y, v are only known at runtime
    int x = 4;
    int y = 6;
    int v = 3;

    int result = 0;

    if (x == 1 && y == 1) result = foo<1, 1>(v);
    if (x == 1 && y == 3) result = foo<1, 3>(v);
    if (x == 5 && y == 1) result = foo<5, 1>(v);
    if (x == 4 && y == 6) result = foo<4, 6>(v);
    if (x == 8 && y == 4) result = foo<8, 4>(v);
    // ...

    std::cout << result << std::endl;
}

我想为XY 的不同组合实例化foo,如main 中的if 级联所示。

然而,这可能会变得非常丑陋(长)。在给定所需组合列表的情况下,是否有可能使用 C++14(例如通过使用预处理器)生成此代码?

【问题讨论】:

  • 为什么不使用可变参数模板参数列表,由所需组合对组成?
  • @user0042:我不知道这是可能的。但是避免预处理器的解决方案当然可以。 ;-)
  • Related,可能是骗子。

标签: c++ templates c-preprocessor c++14 template-instantiation


【解决方案1】:

这是一个使用递归的版本。

#include <iostream>
#include <utility>
#include <stdexcept>

template <int X, int Y>
int foo(int v) // dummy parameter
{
    return v * X + v / Y; // dummy calculation
}

template <std::size_t index = 0>
int foo(int x, int y, int v) {
    constexpr std::pair<int, int> numbers[] = {{1, 1}, {1, 3}, {5, 1}, {4, 6}, {8, 4}};
    if constexpr (index < sizeof numbers / sizeof *numbers) {
        if (numbers[index].first == x && numbers[index].second == y) {
            return foo<numbers[index].first, numbers[index].second>(v);
        }
        return foo<index + 1>(x, y, v);
    } else { //no match
        throw std::runtime_error("No matching pair found");
    }
}

int main() {
    // x, y, v are only known at runtime
    int x = 4;
    int y = 6;
    int v = 3;

    int result = foo(x, y, v);

    std::cout << result << std::endl;
}

如果您没有 C++17,您可以将 if constexpr 替换为标签调度。 Both clang and gcc manage to optimize out the code starting at -O1.

【讨论】:

  • 很好,我认为从 C++14 开始,你应该能够使 foo constexpr 因为 throw 应该只在错误时使用,然后你得到一个错误。
【解决方案2】:

为已知的 x 和 y 对生成代码和实例很容易,如果这正是您想要的。

#define XYLIST \
X(1,1)\
X(1,3)\
X(5,1)\
X(4,6)\
X(8,4)
// etc.

#define X(X1, Y1) \
if (X1 == 1 && Y1 == 1) result = foo<X1, Y1>(v); else

XYLIST
{ throw "failed"; }

#undef X

添加了“else”,因为不应有两行相同。并在末尾“抛出”以完成 else 级联。

【讨论】:

  • 谢谢!我used你的解决方案。 :)
【解决方案3】:

您可以将它们转换为常量表达式。如果事先知道 incase 值

#include <iostream>

template <int X, int Y>
int foo(int v) // dummy parameter
{
    return v * X + v / Y; // dummy calculation
}

int main()
{
    // x, y, v are only known at runtime
    const int x = 4;
    const int y = 6;
    int v = 3;

   int result = 0;

   result = foo<x, y>(v);


    std::cout << result << std::endl;
}

但是,模板不是要执行的算法,而是要扩展以生成代码的宏。 我不建议对相同的 data type 使用模板,在这种情况下,您只使用 int。因此,根据编码标准,模板并不是特别需要。

在函数本身中传递这些值。

方法一:如果你只有整数。

int foo(int v, int X, int Y) // dummy parameter
{
    return v * X + v / Y; // dummy calculation
}
int main()
{
    // x, y, v are only known at runtime
    int x = 4;
    int y = 6;
    int v = 3;

    int result = 0;

    result = foo(v,x,y);
}

方法二:如果什么都可以传,即双data-type

template <typename T>
T foo(int v, T Y, T Y) // dummy parameter
{
    return v * X + v / Y; // dummy calculation
}

【讨论】:

  • 谢谢,但我知道在上述情况下,只需在运行时传递每个值的整数参数。 ;-) 这只是一个最小的例子,一个简化版本的问题,在编译时知道一些参数有利于性能(深度学习库中的 libEigen 矩阵的大小和一个 conv 层的 im2col 实现)。
  • 为什么不建议对相同数据类型使用模板?非类型模板很有用。
猜你喜欢
  • 2010-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-15
  • 1970-01-01
相关资源
最近更新 更多