我使用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?

最佳答案

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

10-08 11:24