[英]Templates linker error: Undefined symbols (linker error), but everything in one file
編譯和鏈接定義自定義文字的唯一文件失敗。 該文件由自定義文字定義( operator""
)組成,在此之前,有一個模板類將數字( typename ... Chars
)轉換為NumberT
類型的NumberT
:
#include <cstdint>
#include <chrono>
#include <limits>
using Du = std::chrono::duration<uint16_t>;
template <typename NumberT, size_t Depth, char ... String>
struct _StringToNumber;
template <typename NumberT, size_t Depth, char Head, char ... Tail>
struct _StringToNumber<NumberT, Depth, Head, Tail ...> {
static_assert('0' <= Head <= '9', "unsupported character in unsigned number literal");
using next = _StringToNumber<NumberT, Depth+1, Tail ...>;
const static size_t total_depth = next::total_depth;
const static NumberT order_value = (total_depth-Depth-1)*(Head - '0');
static_assert(std::numeric_limits<NumberT>::max() - next::value >= order_value, "literal does not fit the underlying type");
const static NumberT value = order_value + next::value;
};
template <typename NumberT, size_t Depth>
struct _StringToNumber<NumberT, Depth> {
const static size_t total_depth = Depth;
const static NumberT value = 0;
};
template <typename NumberT, char ... Chars>
using StringToNumber = _StringToNumber<NumberT, 0, Chars ...>;
template <char ... Chars>
Du operator "" _du () { // my custom literal
return Du(StringToNumber<Du::rep, Chars ...>::value);
}
int main() {
1_du; // Undefined symbols for architecture x86_64: "_StringToNumber<unsigned short, 0ul, (char)49>::value"
StringToNumber<uint16_t, '2'>::value; // apparently works
return 0;
}
鏈接器錯誤:
Undefined symbols for architecture x86_64:
"_StringToNumber<unsigned short, 0ul, (char)49>::value", referenced from:
std::__1::chrono::duration<unsigned short, std::__1::ratio<1l, 1l> > operator"" _du<(char)49>() in scratch_1-71f359.o
ld: symbol(s) not found for architecture x86_64
奇怪的是,如果我用例如uint16_t替換Du和Du :: rep,我不會收到錯誤。
命令g++ -std=c++17 thefile.cpp
$ g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 10.0.0 (clang-1000.11.45.5)
Target: x86_64-apple-darwin18.0.0
Thread model: posix
struct
定義內的以下語法:
const static NumberT value = 0;
是帶有初始化程序的聲明, 而不是定義。 也就是說,編譯器可以將其值用於優化目的,但是一旦value
被ODR使用(例如,綁定到引用),該實體就必須在內存中具有地址。 通過使用std::chrono::duration
作為operator""
的結果,您可以強制value
受duration
的構造函數接受作為參數的引用的約束,因此允許鏈接器抱怨缺少的定義。 為了提供定義,請在struct
本身的定義之后添加以下幾行:
template <typename NumberT, size_t Depth>
const NumberT _StringToNumber<NumberT, Depth>::value;
在專業化之后:
template <typename NumberT, size_t Depth, char Head, char ... Tail>
const NumberT _StringToNumber<NumberT, Depth, Head, Tail ...>::value;
或者使所有聲明都inline
( c ++ 17 ):
template <typename NumberT, size_t Depth>
struct _StringToNumber<NumberT, Depth> {
inline const static size_t total_depth = Depth;
inline const static NumberT value = 0;
};
還要注意,標識符以下划線開頭,后跟大寫字母,為實現保留。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.