假设我有一些类似如下的代码
Convert.hpp
#pragma once
#include <cassert>
class Converter
{
public:
template <typename T>
static inline void to_type(const char* bytes, T& val);
static inline void to_int(const char* bytes, int& val);
};
#include "converter.inl"
Convert.inl
template <typename T>
void Converter::to_type(const char* bytes, T& value)
{
auto numberOfBytes = sizeof(T);
if (numberOfBytes == 8)
{
value = (T)(*(bytes + 3) << 40 | *(bytes + 3) << 32 | *(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
}
else if (numberOfBytes == 4)
{
value = (T)(*(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
}
else if (numberOfBytes == 2)
{
value = (T)(*(bytes + 1) << 8 | *bytes);
}
else {
assert(false);
}
}
void Converter::to_int(const char* bytes, int& value)
{
to_type(bytes, value);
}
Userofconverter.hpp
#pragma once
bool isConverterUsed(const char* bytes);
Userofconverter.cpp
#include <iostream>
#include "converter.hpp"
bool isConverterUsed(const char* bytes)
{
int myIntValue = 0;
Converter::to_type(bytes, myIntValue);
std::cout << "myIntValue: " << myIntValue << std::endl;
return true;
}
converter.hpp的另一个用户
#pragma once
bool isConverterUsedAgain(const char* bytes);
converter.cpp的另一个用户
#include <iostream>
#include "converter.hpp"
bool isConverterUsedAgain(const char* bytes)
{
int myIntValue = 0;
Converter::to_type(bytes, myIntValue);
std::cout << "myIntValue: " << myIntValue << std::endl;
return true;
}
此代码除了帮助我说明问题外无所作为。当我使用g++ (Ubuntu 8.3.0-6ubuntu1~18.04) 8.3.0
进行编译时(如果在WSL中很重要),我得到以下输出
$g++ main.cpp userofconverter.cpp anotheruserofconverter.cpp
In file included from converter.hpp:13,
from userofconverter.cpp:3:
converter.inl: In static member function ‘static void Converter::to_type(const char*, T&)’:
converter.inl:7:31: warning: left shift count >= width of type [-Wshift-count-overflow]
value = (T)(*(bytes + 3) << 40 | *(bytes + 3) << 32 | *(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
^~
converter.inl:7:52: warning: left shift count >= width of type [-Wshift-count-overflow]
value = (T)(*(bytes + 3) << 40 | *(bytes + 3) << 32 | *(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
^~
converter.inl: In instantiation of ‘static void Converter::to_type(const char*, T&) [with T = int]’:
converter.inl:24:23: required from here
converter.inl:7:28: warning: left shift count >= width of type [-Wshift-count-overflow]
value = (T)(*(bytes + 3) << 40 | *(bytes + 3) << 32 | *(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
~~~~~~~~~~~~~^~~~~
converter.inl:7:49: warning: left shift count >= width of type [-Wshift-count-overflow]
value = (T)(*(bytes + 3) << 40 | *(bytes + 3) << 32 | *(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
~~~~~~~~~~~~~^~~~~
In file included from converter.hpp:13,
from anotheruserofconverter.cpp:3:
converter.inl: In static member function ‘static void Converter::to_type(const char*, T&)’:
converter.inl:7:31: warning: left shift count >= width of type [-Wshift-count-overflow]
value = (T)(*(bytes + 3) << 40 | *(bytes + 3) << 32 | *(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
^~
converter.inl:7:52: warning: left shift count >= width of type [-Wshift-count-overflow]
value = (T)(*(bytes + 3) << 40 | *(bytes + 3) << 32 | *(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
^~
converter.inl: In instantiation of ‘static void Converter::to_type(const char*, T&) [with T = int]’:
converter.inl:24:23: required from here
converter.inl:7:28: warning: left shift count >= width of type [-Wshift-count-overflow]
value = (T)(*(bytes + 3) << 40 | *(bytes + 3) << 32 | *(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
~~~~~~~~~~~~~^~~~~
converter.inl:7:49: warning: left shift count >= width of type [-Wshift-count-overflow]
value = (T)(*(bytes + 3) << 40 | *(bytes + 3) << 32 | *(bytes + 3) << 24 | *(bytes + 2) << 16 | *(bytes + 1) << 8 | *bytes);
~~~~~~~~~~~~~^~~~~
在编译输出中,我可以看到两次此消息In instantiation of ‘static void Converter::to_type(const char*, T&) [with T = int]’
答案 0 :(得分:2)
模板将被编译两次。这是因为内联函数是在标头中定义的,并且未编译标头,因此每个cpp文件必须编译其使用的每个内联函数的自身版本,以防万一其他cpp文件不使用内联函数。但是,如果编译器内联了内联函数,则仍然有必要,并且如果内联函数未内联,则链接器将删除重复项。
您可以在cpp文件中为Converter :: to_type
// file Converter.h
#pragma once
#include <cassert>
class Converter
{
public:
template <typename T>
static inline void to_type(const char* bytes, T& val);
...
};
extern template void Converter::to_type<int>(const char* bytes, int& val);
...
// file Converter.cpp
#include "Converter.h"
template void Converter::to_type<int>(const char* bytes, int& val);
答案 1 :(得分:0)
Converter::to_type
作为实例化跟踪的一部分,在错误消息中多次出现。为什么在特定的to_type
实例中有两个错误?可能是因为您没有使用constexpr
numberOfBytes
和if constexpr
,所以to_type
中的所有代码都必须有效并进行编译。如果if constexpr
不可用,您仍然可以使用模板专门化来模拟它。
答案 2 :(得分:0)
您编译了3个cpp文件g++ main.cpp userofconverter.cpp anotheruserofconverter.cpp
,命令行中的每个cpp文件都会生成一个Translation unit。
每个翻译单元都会#include "converter.hpp"
,因为您告诉过它,并且在编译这两个翻译单元时,它们都在converter.hpp
中发现了警告和错误,因此您会看到相同的消息。
是的,它可以解决,例如,您可以编译一个文件(例如main.cpp
)并包含userofconverter.cpp
和anotheruserofconverter.cpp
,它将作为一个翻译单元编译。