简体   繁体   English

使用不完整(部分指定)模板化类型强制模板特化

[英]force template specialization with an incomplete (partially specified) templated type

I am encountering some issues when I try to force template specialization with an incomplete (partially specified) templated type.当我尝试使用不完整(部分指定)的模板化类型强制进行模板专业化时,我遇到了一些问题。

Let's consider this oversimplified example: I have a template function declaration for which I provide forced specification for some common types in the corresponding C++ file.让我们考虑这个过于简单的示例:我有一个模板 function 声明,我在相应的 C++ 文件中为某些常见类型提供了强制规范。

in.h file:在.h文件中:

template <class T>
void doSomething(const T &value);

in cpp file:在.cpp文件中:

// force template specializations with various types
template <>
void doSomething<float>(const float &value)
{
  // actual code specialization for type float, es:
  printf("%.3f", value);
}
...

and for example, I want to do the same specialization for glm vector (from OpenGL Mathematics library), which is templated on the number of components and on the data type of its components (and also on precision, that I will skip in this example for clarity).例如,我想对glm 向量(来自 OpenGL 数学库)进行相同的专业化,它根据组件的数量和组件的数据类型(以及精度,我将在本例中跳过)进行模板化为清楚起见)。

What I would like to avoid is to explicitly write the actual specialization for all possible values of N (leading to code repetition, since it is basically the same loop but with different number of iterations), as shown here:我想避免的是为 N 的所有可能值显式编写实际特化(导致代码重复,因为它基本上是相同的循环,但迭代次数不同),如下所示:

template <>
void doSomething<glm::vec<2, float>>(const glm::vec<2, float> &value)
{
  printf("{");
  printf("%.3f", value[0]);
  for (int i = 1; i< 2 ++i)
    printf(", %.3f", value[i]);
  printf("}");
}

template <>
void doSomething<glm::vec<3, float>>(const glm::vec<3, float> &value)
{
  printf("{");
  printf("%.3f", value[0]);
  for (int i = 1; i< 3 ++i)
    printf(", %.3f", value[i]);
  printf("}");
}

template <>
void doSomething<glm::vec<4, float>>(const glm::vec<4, float> &value)
{
  printf("{");
  printf("%.3f", value[0]);
  for (int i = 1; i< 4 ++i)
    printf(", %.3f", value[i]);
  printf("}");
}

What I would like to do is writing something like this:我想做的是写这样的东西:

template <glm::length_t N>
void doSomething<glm::vec<N, float>>(const glm::vec<N, float> &value)
{
  printf("{");
  printf("%.3f", value[0]);
  for (int i = 1; i< N ++i)
    printf(", %.3f", value[i]);
  printf("}"); 
}
// force full template specializations
template void doSomething<glm::vec<2, float>>(const glm::vec<2, float> &value);
template void doSomething<glm::vec<3, float>>(const glm::vec<3, float> &value);
template void doSomething<glm::vec<4, float>>(const glm::vec<4, float> &value);

but this solution arises the following compilation error: "illegal use of explicit template arguments"但此解决方案出现以下编译错误:“非法使用显式模板参数”

I have read that "Function partial specialization" is not allowed in C++, is this limitation still valid in modern standards C++ (14/17/20)?我读到 C++ 不允许“功能部分专业化”,这个限制在现代标准 C++ (14/17/20) 中是否仍然有效? Is this the cause of the issue or maybe I am missing something?这是问题的原因还是我遗漏了什么? Thank you all in advance.谢谢大家。

Partial Function Specialization is not allowed.部分 Function 不允许特化。 However, you can avoid explicitly writing the code for all possible values of N by using Function Overloading.但是,您可以通过使用 Function 重载来避免为 N 的所有可能值显式编写代码。 The example below is based on your code, but I've replaced glm::vec<> with std::array<> since they are similar.下面的示例基于您的代码,但我已将glm::vec<>替换为std::array<>因为它们相似。 Also, I only used a .C file for convenience.另外,为了方便起见,我只使用了.C文件。

#include <cstdio>
#include <iostream>
#include <array>

using namespace std;

// Overload the function for various types
void doSomething(const float &value)
{
  // actual code for type float:
  printf("%.3f", value);
}

// overloading not specialization
template<std::size_t N>
void doSomething(array<float, N> &value)
{
    printf("{");
    printf("%.3f", value[0]);
    for (int i = 1; i < N; ++i)
        printf(", %.3f", value[i]);
    printf("}");
}

int main()
{
    float f = 5.0;
    doSomething(f);
    cout << endl;

    std::array<float, 3> a1 = {1, 2, 3};
    doSomething<3>(a1);
    cout << endl;

    std::array<float, 4> a2 = {1, 2, 3, 4};
    doSomething<4>(a2);
    cout << endl;
}

Here is the output:这是 output:

$ g++ --version
Apple clang version 13.1.6 (clang-1316.0.21.2.5)
$ g++ -std=c++17 doSomething.C 
$ a.out
5.000
{1.000, 2.000, 3.000}
{1.000, 2.000, 3.000, 4.000} 
$

As an alternative to Luis' answer with overloading, you can also add an additional level of abstraction.作为 Luis 的超载答案的替代方案,您还可以添加额外的抽象级别。 You can write a separate function that handles the array and then call it from within doSomething :您可以编写一个单独的 function 来处理数组,然后从doSomething中调用它:

template<std::size_t N>
void doSomethingForArray(array<float, N> &value)
{
    printf("{");
    printf("%.3f", value[0]);
    for (int i = 1; i < N; ++i)
        printf(", %.3f", value[i]);
    printf("}");
}

template <>
void doSomething<glm::vec<2, float>>(const glm::vec<2, float> &value)
{ doSomethingForArray(value); }

template <>
void doSomething<glm::vec<3, float>>(const glm::vec<3, float> &value)
{ doSomethingForArray(value); }


template <>
void doSomething<glm::vec<4, float>>(const glm::vec<4, float> &value)
{ doSomethingForArray(value); }

Given that your original solution still requires to explicitly instantiate all 3 functions, I don't think this is much of an overhead.鉴于您的原始解决方案仍然需要显式实例化所有 3 个函数,我认为这不是很大的开销。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM