将 c 风格的字符串自动解释为 std::string 到 Boost Property tree .get 函数

Posted

技术标签:

【中文标题】将 c 风格的字符串自动解释为 std::string 到 Boost Property tree .get 函数【英文标题】:Auto-interpreting a c-style string as a std::string via Boost's Property tree's .get function 【发布时间】:2016-06-15 19:21:03 【问题描述】:

我使用 boosts 属性树,包括通过

#include "boost\property_tree\ptree.hpp"

而且...我想创建一个简单的函数来替换一个值,以防通过相当直接的模板函数找到一个值:

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?

【问题讨论】:

我不记得有这个问题,尽管我在心理上预计会有它。由此我得出结论,Boost Property 已经实现了适当的“DWIM”功能。你用的是哪个版本的boost? (从包含路径拼写我得到的印象是你用的是 MSVC,哪个版本?) 【参考方案1】:

您可以提供 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;

live example


另一种解决方案是使用自定义类型特征:

#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;

live example

【讨论】:

【参考方案2】:

我发现的唯一方法是将getValueOrDefault 专门用于const char*,它使用std::string 显式调用getValueOrDefault

//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();

如果您希望该函数返回 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);

【讨论】:

const char* 重载不需要是模板,它可以是返回std::string 的“常规”函数 字符串文字 ""s 需要 C++14(与 OP 的 C++11 标签冲突) @m.s 谢谢 :) 但我仍然会保留文字作为选项,他没有明确提到 C++14 是被禁止的。

以上是关于将 c 风格的字符串自动解释为 std::string 到 Boost Property tree .get 函数的主要内容,如果未能解决你的问题,请参考以下文章

是 包含时自动包含

c++ string中取某一部分字符串

c++ string中取某一部分字符串

将 C 风格的字符串转换为 C++ std::string

如何将 std::string 转换为 C 风格的字符串 [重复]

string字符串转C风格字符串 进而转换为数字