'template specialization in header causes Linking issues
I am playing around with converting standard library functions like stoi to not throw exceptions on failures but keep running into linking issues. I followed steps from other similar questions but the linker is still not satisfied
Header.h
#include <optional>
#include <iostream>
#include <string>
#include <cstddef>
namespace temp{
template<class T>
std::optional<int> noexcept_stoi( const T& str, std::size_t* pos = nullptr, int base = 10)
{
//body of the function
}
template<> inline std::optional<int> noexcept_stoi<std::wstring>( const std::wstring& str, std::size_t* pos, int base );
template<> inline std::optional<int> noexcept_stoi<std::string>( const std::string& str, std::size_t* pos, int base );
};
Test.cpp
#include "Header.h"
int main(){
std::string input = "123";
auto result = temp::safe_stoi(input);
return 0;
}
Error: Undefined symbols for architecture arm64: "std::__1::optional temp::noexcept_stoi<std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator > >(std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator > const&, unsigned long*, int)"
What am I missing ?
Solution 1:[1]
The problem is that you have only provided the declarations for the specializations and not the corresponding definition. There are two ways to solve this as given below:
Method 1
Here we provide the corresponding definition for the specializations.
namespace temp{
template<class T>
std::optional<int> noexcept_stoi( const T& str, std::size_t* pos = nullptr, int base = 10)
{
return 4; //don't forget to return something
}
template<> inline std::optional<int> noexcept_stoi<std::wstring>( const std::wstring& str, std::size_t* pos, int base )
{
return 4;
}
template<> inline std::optional<int> noexcept_stoi<std::string>( const std::string& str, std::size_t* pos, int base )
{
return 4;
}
};
Method 2
We could make use of explicit template instantiation to solve this problem as shown below.
Header.h
#ifndef MYHEADER_H
#define MYHEADER_H
#include <optional>
#include <iostream>
#include <string>
#include <cstddef>
namespace temp{
template<class T>
std::optional<int> noexcept_stoi( const T& str, std::size_t* pos = nullptr, int base = 10)
{
return 4; //return something
}
//-----------------v------------------------->no need for angle brackets as well as inline
extern template std::optional<int> noexcept_stoi<std::wstring>( const std::wstring& str, std::size_t* pos, int base );
//-----------------v------------------------->no need for angle brackets as well as inline
extern template std::optional<int> noexcept_stoi<std::string>( const std::string& str, std::size_t* pos, int base );
};
#endif
main.cpp
#include <iostream>
#include "Header.h"
//explicit template instantiation definition
template std::optional<int> temp::noexcept_stoi<std::wstring>( const std::wstring& str, std::size_t* pos, int base );
template std::optional<int> temp::noexcept_stoi<std::string>( const std::string& str, std::size_t* pos, int base );
int main(){
std::string input = "123";
auto result = temp::noexcept_stoi(input);
return 0;
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
