通过 Boost 的 属性 树的 .get 函数将 c 风格的字符串自动解释为 std::string
Auto-interpreting a c-style string as a std::string via Boost's Property tree's .get function
我使用 boosts 属性 树,包含在
#include "boost\property_tree\ptree.hpp"
并且...我想创建一个简单的函数来替换一个值,以防通过相当直接的模板函数找到 none:
template <typename Type>
Type getValueOrDefault( std::string const& str, Type defaultValue )
{
Type returnValue = defaultValue;
try {
returnValue = mSettings.get<Type>( str );
}
catch ( boost::property_tree::ptree_error &e )
{
// Log error!
}
return returnValue;
}
原则上这很好用,但如果我依赖 C 风格的字符串,就会遇到一些问题。例如调用函数如下:
getValueOrDefault( "pathToImportantStuffParameter", "c:/defaultdir/" )
会导致以下错误:
boost\property_tree\stream_translator.hpp(36): error C2678: binary '>>' : no operator found which takes a left-hand operand of type 'std::basic_istream<char,std::char_traits<char>>' (or there is no acceptable conversion)
错误源于将 char const *
作为模板参数传递,这很合理。这个问题的两个明显解决方案是将默认值强制为 std::string 对象,如下所示:
getValueOrDefault<std::string>( "pathToImportantStuffParameter", "c:/defaultdir/" )
getValueOrDefault( "pathToImportantStuffParameter", std::string("c:/defaultdir/") )
但我想知道是否有人知道我可以使用一些模板魔法来自动将 c 风格的字符串解释为 std::strings?
我发现的唯一方法是将 getValueOrDefault
专门化为 const char*
,它显式调用 getValueOrDefault
和 std::string
:
//Note that the return value is unspecified, it returns a 'const char*' to a temporary,
//which will be destroyed when the function returns
template <>
const char* getValueOrDefault(std::string const& str, const char* defaultValue)
{
return getValueOrDefault<std::string>(str, defaultValue).c_str();
}
如果您想将该函数 return 变成 std::string
而不是无效的 const char*
,您必须稍微更改模板签名:
//Default return type is the same as paramter
template <typename Type, typename Return = Type>
Return getValueOrDefault(std::string const& str, Type defaultValue)
{
//...
}
//Trick the compiler to select this overload for 'const char*'
template <typename Return = std::string>
Return getValueOrDefault(std::string const& str, const char* defaultValue)
{
return getValueOrDefault<std::string, std::string>(str, defaultValue);
}
或者你可以简单地重载函数(感谢@m.s。)
//Overload for 'const char*'
std::string getValueOrDefault(std::string const& str, const char* defaultValue)
{
return getValueOrDefault<std::string>(str, defaultValue);
}
还有第三种方式(如果你可以使用C++14),使用字符串文字""s
:
//"c:/defaultdir/"s is a std::string (note the s after it => string literal)
getValueOrDefault("pathToImportantStuffParameter", "c:/defaultdir/"s);
您可以提供一个 char 数组重载,将 char 数组转换为 std::string
,然后调用默认实现:
#include <iostream>
#include <string>
template <typename T>
T getValueOrDefault(const std::string& str, T&& defaultValue)
{
std::cout << "inside default implementation" << std::endl;
/* ... */
return defaultValue;
}
template <std::size_t N>
std::string getValueOrDefault(const std::string& str, const char (&defaultValue)[N])
{
std::cout << "inside char[] overload" << std::endl;
return getValueOrDefault(str, std::string(defaultValue));
}
int main()
{
auto x = getValueOrDefault("foo", "bar");
return 0;
}
另一种解决方案是使用自定义类型特征:
#include <string>
#include <type_traits>
template <typename T>
struct return_type
{
using type = T;
};
template <>
struct return_type<const char*>
{
using type = std::string;
};
template <typename T>
using return_type_t = typename return_type<typename std::decay<T>::type>::type;
template <typename T>
return_type_t<T> getValueOrDefault(const std::string& str, T&& defaultValue)
{
return_type_t<T> value(defaultValue);
/* ... */
return value;
}
int main()
{
auto x = getValueOrDefault("foo", "bar");
static_assert(std::is_same<decltype(x), std::string>::value, "");
return 0;
}
我使用 boosts 属性 树,包含在
#include "boost\property_tree\ptree.hpp"
并且...我想创建一个简单的函数来替换一个值,以防通过相当直接的模板函数找到 none:
template <typename Type>
Type getValueOrDefault( std::string const& str, Type defaultValue )
{
Type returnValue = defaultValue;
try {
returnValue = mSettings.get<Type>( str );
}
catch ( boost::property_tree::ptree_error &e )
{
// Log error!
}
return returnValue;
}
原则上这很好用,但如果我依赖 C 风格的字符串,就会遇到一些问题。例如调用函数如下:
getValueOrDefault( "pathToImportantStuffParameter", "c:/defaultdir/" )
会导致以下错误:
boost\property_tree\stream_translator.hpp(36): error C2678: binary '>>' : no operator found which takes a left-hand operand of type 'std::basic_istream<char,std::char_traits<char>>' (or there is no acceptable conversion)
错误源于将 char const *
作为模板参数传递,这很合理。这个问题的两个明显解决方案是将默认值强制为 std::string 对象,如下所示:
getValueOrDefault<std::string>( "pathToImportantStuffParameter", "c:/defaultdir/" )
getValueOrDefault( "pathToImportantStuffParameter", std::string("c:/defaultdir/") )
但我想知道是否有人知道我可以使用一些模板魔法来自动将 c 风格的字符串解释为 std::strings?
我发现的唯一方法是将 getValueOrDefault
专门化为 const char*
,它显式调用 getValueOrDefault
和 std::string
:
//Note that the return value is unspecified, it returns a 'const char*' to a temporary,
//which will be destroyed when the function returns
template <>
const char* getValueOrDefault(std::string const& str, const char* defaultValue)
{
return getValueOrDefault<std::string>(str, defaultValue).c_str();
}
如果您想将该函数 return 变成 std::string
而不是无效的 const char*
,您必须稍微更改模板签名:
//Default return type is the same as paramter
template <typename Type, typename Return = Type>
Return getValueOrDefault(std::string const& str, Type defaultValue)
{
//...
}
//Trick the compiler to select this overload for 'const char*'
template <typename Return = std::string>
Return getValueOrDefault(std::string const& str, const char* defaultValue)
{
return getValueOrDefault<std::string, std::string>(str, defaultValue);
}
或者你可以简单地重载函数(感谢@m.s。)
//Overload for 'const char*'
std::string getValueOrDefault(std::string const& str, const char* defaultValue)
{
return getValueOrDefault<std::string>(str, defaultValue);
}
还有第三种方式(如果你可以使用C++14),使用字符串文字""s
:
//"c:/defaultdir/"s is a std::string (note the s after it => string literal)
getValueOrDefault("pathToImportantStuffParameter", "c:/defaultdir/"s);
您可以提供一个 char 数组重载,将 char 数组转换为 std::string
,然后调用默认实现:
#include <iostream>
#include <string>
template <typename T>
T getValueOrDefault(const std::string& str, T&& defaultValue)
{
std::cout << "inside default implementation" << std::endl;
/* ... */
return defaultValue;
}
template <std::size_t N>
std::string getValueOrDefault(const std::string& str, const char (&defaultValue)[N])
{
std::cout << "inside char[] overload" << std::endl;
return getValueOrDefault(str, std::string(defaultValue));
}
int main()
{
auto x = getValueOrDefault("foo", "bar");
return 0;
}
另一种解决方案是使用自定义类型特征:
#include <string>
#include <type_traits>
template <typename T>
struct return_type
{
using type = T;
};
template <>
struct return_type<const char*>
{
using type = std::string;
};
template <typename T>
using return_type_t = typename return_type<typename std::decay<T>::type>::type;
template <typename T>
return_type_t<T> getValueOrDefault(const std::string& str, T&& defaultValue)
{
return_type_t<T> value(defaultValue);
/* ... */
return value;
}
int main()
{
auto x = getValueOrDefault("foo", "bar");
static_assert(std::is_same<decltype(x), std::string>::value, "");
return 0;
}