如何简洁地编写许多显式的函数模板实例化? [英] How can I concisely write a lot of explicit function template instantiations?

查看:227
本文介绍了如何简洁地编写许多显式的函数模板实例化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个C ++库,其中包含许多函数模板,我想显式实例化并导出几个类型参数.在我的特殊情况下,我有很多数字函数模板,我想分别实例化并为floatdoublelong double进行编译.他们看起来像这样:

I'm writing a C++ library that contains a lot of function templates I want to explicitly instantiate and export for several type parameters. In my particular case, I have a lot of numeric function templates that I want to separately instantiate and compile for float, double, and long double. They look something like this:

template <typename T>
T calculate_a(T x) { ... }

template <typename T>
T calculate_b(T x, T y) { ... }

// ...

如果我有M个功能模板和N个基础类型,那么我有M * N个显式实例可输入.是否可以更简洁地编写这些实例?

If I have M function templates and N underlying types, then I have M*N explicit instantiations to type out. Is it possible to write these instantiations more concisely?

我当前的解决方案是使用预处理器宏,该宏对给定类型执行所有实例化:

My current solution is to use a preprocessor macro that performs all instantiations for a given type:

#define EXPLICITLY_INSTANTIATE(T) \
    template T calculate_a<T>(T x); \
    template T calculate_b<T>(T x, T y); \
    // ...

EXPLICITLY_INSTANTIATE(float);
EXPLICITLY_INSTANTIATE(double);
EXPLICITLY_INSTANTIATE(long double);

但是,这不是最理想的,因为它要求我分别维护每个功能模板签名的另一个副本.另外,如果我想在多个翻译单元中执行此操作,则需要分别维护每个基础类型的列表. (假设C ++ 2a添加了我要支持的long long double类型;我必须在每个文件中添加EXPLICITLY_INSTANTIATE(long long double);.)

However, this is suboptimal because it requires me to separately maintain another copy of each function template's signature. Also, if I want to do this in multiple translation units, then I need to separately maintain a list of underlying types in each. (Suppose that C++2a adds a long long double type that I want to support; I'll have to add EXPLICITLY_INSTANTIATE(long long double); to every file.)

另一种可能的方法是将我所有的功能收集到一个(仅静态的)模板类中:

Another possible approach is to gather up all of my functions into a (static-only) template class:

template <typename T>
class calculate {
    T a(T x) { ... }
    T b(T x, T y) { ... }
};

template class calculate<float>;
template class calculate<double>;
template class calculate<long double>;

这解决了第一个问题,即分别维护每个签名的两个副本,但是要求我将每个calculate_a调用都更改为calculate::a<T>.它没有解决第二个问题.

This solves the first problem of separately maintaining two copies of each signature, but requires me to change each call of calculate_a into calculate::a<T>. It doesn't address the second problem.

推荐答案

您可以通过采用其地址实例化模板来避免重复函数签名:

You can avoid repeating function signatures by instantiating templates via taking their addresses:

// forward declarations in a header file
template<typename T>
T square(T num);

template<typename T>
T add(T left, T right);

// implementations and instantiations in a single implementation file
template<typename T>
T square(T num) {
    return num * num;
}

template<typename T>
T add(T left, T right) {
    return left + right;
}

// instantiations for specific types
#include <tuple>

template<typename... Ts>
auto instantiate() {
    static auto funcs = std::tuple_cat(std::make_tuple(
        add<Ts>,
        square<Ts>
    )...);

    return &funcs;
}

template auto instantiate<int, double>();

这里的开销是指向所有实例化函数的单个指针数组,例如 godbolt 上的示例.

The overhead here is a single array of pointers to all instantiated functions, example on godbolt.

这篇关于如何简洁地编写许多显式的函数模板实例化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆