为什么 std::is_same 总是给我一个编译错误
Why does std::is_same always give me a compiling error
在我的项目中,有一些配置文件。我需要将它们提取为整数或字符串。为此,我编写了如下函数:
template<typename T>
void loadTxtConfig(const std::string& filename, std::set<T>& ids) {
std::ifstream infile(filename);
if (!infile) {
return;
}
std::string line;
if (std::is_integral<T>::value) {
while (std::getline(infile, line)) {
ids.emplace(static_cast<T>(std::stoll(line))); // noexcept
}
} else if (std::is_same<T, std::string>::value) {
while (std::getline(infile, line)) {
ids.emplace(line);
}
}
}
我试着这样称呼它:
std::set<int> intCfg;
std::set<std::string> strCfg;
loadTxtConfig("./conf/int.txt", intCfg);
loadTxtConfig("./conf/str.txt", strCfg);
但是我编译的时候总是报模板错误:
/usr/include/c++/5/ext/new_allocator.h:120:4: error: cannot convert ‘std::__cxx11::basic_string<char>’ to ‘int’ in initialization
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
我做错了什么?
问题是,if
的 statement-true 和 statement-false 都需要在编译时有效-time,即使其中之一也不会在 运行-time 进行评估。当 T
为 int
时 ids.emplace(line);
会导致错误。
您可以使用 Constexpr If(C++17 起)。
If the value is true
, then statement-false is discarded (if present), otherwise, statement-true is discarded.
if constexpr (std::is_integral<T>::value) {
while (std::getline(infile, line)) {
ids.emplace(static_cast<T>(std::stoll(line))); // noexcept
}
} else if constexpr (std::is_same<T, std::string>::value) {
while (std::getline(infile, line)) {
ids.emplace(line);
}
}
在 C++17 之前,您可以应用重载。例如
template<typename T>
void loadTxtConfig(const std::string& filename, std::set<T>& ids) {
std::ifstream infile(filename);
if (!infile) {
return;
}
std::string line;
while (std::getline(infile, line)) {
ids.emplace(line);
}
}
void loadTxtConfig(const std::string& filename, std::set<int>& ids) {
std::ifstream infile(filename);
if (!infile) {
return;
}
std::string line;
while (std::getline(infile, line)) {
ids.emplace(static_cast<T>(std::stoll(line))); // noexcept
}
}
在 C++11 中,您必须为不同的类型提供不同版本的函数。
void loadTxtConfig(const std::string& filename, std::set<std::string>& ids) {
std::ifstream infile(filename);
if (!infile) {
return;
}
std::string line;
while (std::getline(infile, line)) {
ids.emplace(line);
}
}
//you could add std::enable_if to only limit the function to integral types,
//but it will only compile if `static_cast<T>(long long)` is valid
template<typename T>
void loadTxtConfig(const std::string& filename, std::set<T>& ids) {
std::ifstream infile(filename);
if (!infile) {
return;
}
std::string line;
while (std::getline(infile, line)) {
ids.emplace(static_cast<T>(std::stoll(line))); // noexcept
}
}
在 C++11 中,我建议您分解参数特定部分(转换)并使用 SFINAE(替换失败不是错误)来使用正确的部分:
#include <type_traits>
template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
T convert(const std::string& line) {
return static_cast<T>(std::stoll(line)); // noexcept
}
template<typename T, typename std::enable_if<std::is_same<T, std::string>::value, int>::type = 0>
const T& convert(const std::string& line) {
return line;
}
template<typename T>
void loadTxtConfig(const std::string& filename, std::set<T>& ids) {
std::ifstream infile(filename);
if (!infile) return;
std::string line;
while (std::getline(infile, line)) {
ids.emplace(convert<T>(line));
}
}
在我的项目中,有一些配置文件。我需要将它们提取为整数或字符串。为此,我编写了如下函数:
template<typename T>
void loadTxtConfig(const std::string& filename, std::set<T>& ids) {
std::ifstream infile(filename);
if (!infile) {
return;
}
std::string line;
if (std::is_integral<T>::value) {
while (std::getline(infile, line)) {
ids.emplace(static_cast<T>(std::stoll(line))); // noexcept
}
} else if (std::is_same<T, std::string>::value) {
while (std::getline(infile, line)) {
ids.emplace(line);
}
}
}
我试着这样称呼它:
std::set<int> intCfg;
std::set<std::string> strCfg;
loadTxtConfig("./conf/int.txt", intCfg);
loadTxtConfig("./conf/str.txt", strCfg);
但是我编译的时候总是报模板错误:
/usr/include/c++/5/ext/new_allocator.h:120:4: error: cannot convert ‘std::__cxx11::basic_string<char>’ to ‘int’ in initialization
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
我做错了什么?
问题是,if
的 statement-true 和 statement-false 都需要在编译时有效-time,即使其中之一也不会在 运行-time 进行评估。当 T
为 int
时 ids.emplace(line);
会导致错误。
您可以使用 Constexpr If(C++17 起)。
If the value is
true
, then statement-false is discarded (if present), otherwise, statement-true is discarded.
if constexpr (std::is_integral<T>::value) {
while (std::getline(infile, line)) {
ids.emplace(static_cast<T>(std::stoll(line))); // noexcept
}
} else if constexpr (std::is_same<T, std::string>::value) {
while (std::getline(infile, line)) {
ids.emplace(line);
}
}
在 C++17 之前,您可以应用重载。例如
template<typename T>
void loadTxtConfig(const std::string& filename, std::set<T>& ids) {
std::ifstream infile(filename);
if (!infile) {
return;
}
std::string line;
while (std::getline(infile, line)) {
ids.emplace(line);
}
}
void loadTxtConfig(const std::string& filename, std::set<int>& ids) {
std::ifstream infile(filename);
if (!infile) {
return;
}
std::string line;
while (std::getline(infile, line)) {
ids.emplace(static_cast<T>(std::stoll(line))); // noexcept
}
}
在 C++11 中,您必须为不同的类型提供不同版本的函数。
void loadTxtConfig(const std::string& filename, std::set<std::string>& ids) {
std::ifstream infile(filename);
if (!infile) {
return;
}
std::string line;
while (std::getline(infile, line)) {
ids.emplace(line);
}
}
//you could add std::enable_if to only limit the function to integral types,
//but it will only compile if `static_cast<T>(long long)` is valid
template<typename T>
void loadTxtConfig(const std::string& filename, std::set<T>& ids) {
std::ifstream infile(filename);
if (!infile) {
return;
}
std::string line;
while (std::getline(infile, line)) {
ids.emplace(static_cast<T>(std::stoll(line))); // noexcept
}
}
在 C++11 中,我建议您分解参数特定部分(转换)并使用 SFINAE(替换失败不是错误)来使用正确的部分:
#include <type_traits>
template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
T convert(const std::string& line) {
return static_cast<T>(std::stoll(line)); // noexcept
}
template<typename T, typename std::enable_if<std::is_same<T, std::string>::value, int>::type = 0>
const T& convert(const std::string& line) {
return line;
}
template<typename T>
void loadTxtConfig(const std::string& filename, std::set<T>& ids) {
std::ifstream infile(filename);
if (!infile) return;
std::string line;
while (std::getline(infile, line)) {
ids.emplace(convert<T>(line));
}
}