C++:显式初始化模板时的隐式转换

问题描述 投票:0回答:1

众所周知,当我们想要在头文件中声明模板化类/函数并在源 cpp 文件中定义它们时,必须在所述 cpp 文件的末尾添加显式初始化 - 限制是,那么,我们的模板将仅适用于明确定义的情况。

例如,假设我们有以下标头,其中包含一个模板化类,该类也具有模板化成员函数:

// header classA.h

template<class T>
class ClassA
{
    /* template<class U> */
    /* friend class ClassA; */
public:
    template<typename U>
    void foo(U val);
};

extern template class ClassA<double>;
extern template void ClassA<double>::foo(double);

这里,

extern
告诉编译器,每当包含此标头时,编译器不应尝试在此处初始化 ClassA 或其成员函数 - 定义将出现在其他地方。

在我们的例子中,它们来自以下 cpp 源文件:

// header classA.cpp

#include <stdio.h>
#include "classA.h"


template<class T>
template<typename U>
void ClassA<T>::foo(U val)
{
    // other code that uses val goes here
    printf("foo\n");
}

template class ClassA<double>;
template void ClassA<double>::foo(double);

我们用这个 main.cpp 测试代码:

#include <stdio.h>
#include "classA.h"

void test(double x) { printf("test\n"); }

int main()
{
    ClassA<int> a;
    float x = 1.0; // this being a float throws a linker error; it must be double
    a.foo(x);
    test(x);
    return 0;
}

上面的代码无法编译,因为

x
float
ld
链接器(使用 G++ 12.3.0)抛出链接错误:

/usr/bin/ld: /tmp/ccVYWPa2.o: 在函数中

main': main.cpp:(.text.startup+0x26): undefined reference to 
void ClassA::foo(float)'collect2: 错误: ld 返回 1 退出 status bash: ./a.out: 没有这样的文件或目录

如果我们将

x
更改为
double
,则程序将按预期编译。也就是说,当
x
float
时,从 float 到 double 的隐式转换不会启动。我不明白的是为什么。当然,一般来说编译器不能明确地决定模板化参数的类型。但是由于给出了显式初始化 - 在这个简单的例子中只有一个 - 我希望编译器在传递给
foo
时隐式地将浮点转换为双精度 - 因为没有其他选项被显式初始化以产生歧义.

也就是说,当显式初始化更多情况时,我当然可以理解歧义:

template class ClassA<double>;
template void ClassA<double>::foo(double);
template class ClassA<double>;
template void ClassA<double>::foo(long double);

所以,我的问题有两个:

  1. 如果没有显式初始化不明确的情况,为什么隐式转换没有发生?

  2. 在这样的例子中,有没有办法强制隐式转换至少当

    T
    =
    U
    时(即可能基于
    T
    类似于类似但不同情况的答案)?

c++ templates implicit-conversion type-traits explicit-instantiation
1个回答
0
投票
  1. 它不是链接,因为
    float
    匹配
    U
    ,然后它正在寻找不存在的定义。
  2. T
    作为函数参数,因此该函数不是模板化的(只是它所属的类)。然后
    a.foo
    将期望一个
    int
    ,这将导致
    a.foo(x)
    进行隐式转换。然后它就无法链接,因为您只提供了
    double
    版本。
© www.soinside.com 2019 - 2024. All rights reserved.