【问题标题】:Overloaded boost::lexical_cast function重载的 boost::lexical_cast 函数
【发布时间】:2014-12-17 14:32:41
【问题描述】:

我想写自己的转换函数&重用 boost::lexical_cast();因此我重载了 boost::lexical_cast() 函数。毕竟,为了同样的目的,boost::conversion::try_lexical_convert() 被添加到库中。

我的程序有效,Overloaded lexical_cast() 在前两种情况下被调用,因为这两个调用都是在本地进行的。在第三种情况下,父函数 boost::lexical_cast() 被调用,因为对 boost::lexical_cast() 的调用是通过 parse_date() 路由的。

我想通过我的 lexical_cast() 函数处理所有转换。即每当调用 boost::lexical_cast() 时,我的重载函数都会被调用。

有什么办法,可以写出这样的全局lexical_cast()函数处理程序

另外,请建议我们如何自定义全局处理程序,使其只能在指定的少数 POD 和 boost 数据类型中调用。

#include <iostream>
#include <string>
#include <exception>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

namespace boost
{
template<typename T>
T lexical_cast(const std::string &str)
{
    if(str.empty()) //handle preconditions here, some custom logic
        return T();

    T result;

    if (!conversion::try_lexical_convert(str, result))
        throw bad_lexical_cast();

    return result;
}
}

using namespace std;
using namespace boost;
using namespace boost::posix_time;
using namespace boost::gregorian;

int main(int ac, char* av[])
{
    try
    {
        //1.
        auto p1_ = lexical_cast<int>(std::string(""));
        std::cout << "p1 = " << p1_ << std::endl; //displays 0, which is correct. calls overloaded lexical_cast()

        //2.
        auto p2_ = lexical_cast<int>(std::string("1"));
        std::cout << "p2 = " << p2_ << std::endl; //displays 1, which is correct. calls overloaded lexical_cast()

        //3.
        std::locale locale_;
        boost::date_time::format_date_parser<boost::gregorian::date, char> parser_("", locale_);
        boost::date_time::special_values_parser<boost::gregorian::date, char> svp_;
        boost::gregorian::date date_ = parser_.parse_date("2014-Dec-17", "%Y-%b-%d", svp_);  //calls boost::lexical_cast(), but I want call to overloaded lexical_cast() instead.
    }
    catch(std::exception& e)
    {
        cout << e.what() << "\n";
        return 1;
    }
    return 0;
}

【问题讨论】:

    标签: c++ c++11 boost


    【解决方案1】:

    您的程序“有效”但与未定义的行为调情。

    在不同的翻译单元中重新定义完全相同的符号的竞争定义在技术上违反了单一定义规则。 您可能会在这里侥幸逃脱,因为它只是关于函数实例,并且一次将可见/选择一个。不过,

    • 这不会使“重载”库功能更有效。
    • 这有能力默默地改变其他代码的行为,包括内部(不可见?)依赖于lexical_cast。特别是对空字符串的默认构造值进行静默“回退”是一种行为变化,图书馆用户可能无法很好地应对。你基本上违反了其他客户与 boost lexical_cast 签订的合同

    只有一种结构模式,即邀请用户在库命名空间内“重载”,即在 扩展点(也称为 TMP 中的自定义点)扩展库时。这通常需要

    • 类的专业化(如std::hash&lt;&gt;boost::hash&lt;&gt;boost::spirit::traits::is_container&lt;&gt;BOOST_FUSION_ADAPT_STRUCT() 等)
    • 添加重载用户定义类型参数的函数的重载(如std::swap,可能是std::iter_swap,但也可能是boost::serialization::serialize重要在这种情况下,通常是命名空间入侵不是首选,实际上也不需要,因为重载可以在命名空间内声明用户定义的类型相关联(例如std::swap(mypgrogram::typeA&amp;, mypgrogram::typeA&amp;) 甚至std::swap(boost::optional&lt;mypgrogram::typeA&gt;&amp;, boost::optional&lt;mypgrogram::typeA&gt;&amp;) 可以很好地在命名空间中定义::mypgrogram),然后编译器可以解决正确的重载,可选地在两阶段查找中,使用参数相关查找 (ADL)

    因此,除非 Boost Lexicalcast 记录了这样一个自定义点供您使用,否则您无法可靠地使其适用于其他模块(也许除了如果你能以某种方式保证你的定义被所有调用看到)。在这种情况下,仅仅改变 Boost Lexicalcast 似乎要简单得多。毕竟这正是你打算做的。

    更新 如果您对 TU 中的包含重新排序,您可以获得所需的效果。请注意使用 SFINAE 来限制(在这种情况下)整数类型

    template<typename T>
        typename std::enable_if<boost::is_integral<T>::value, T>::type 
            lexical_cast(const std::string &str)
    

    Live On Coliru

    #include <iostream>
    #include <string>
    #include <exception>
    #include <boost/lexical_cast.hpp>
    namespace boost
    {
        template<typename T>
            typename std::enable_if<boost::is_integral<T>::value, T>::type 
                lexical_cast(const std::string &str)
            {
                std::cout << __PRETTY_FUNCTION__ << "\n";
                if(str.empty()) //handle preconditions here, some custom logic
                    return T();
    
                T result;
    
                if (!conversion::try_lexical_convert(str, result))
                    throw bad_lexical_cast();
    
                return result;
            }
    }
    
    
    #include <boost/algorithm/string/classification.hpp>
    #include <boost/algorithm/string.hpp>
    #include <boost/date_time/gregorian/gregorian.hpp>
    #include <boost/date_time/posix_time/posix_time.hpp>
    
    using namespace std;
    using namespace boost;
    using namespace boost::posix_time;
    using namespace boost::gregorian;
    
    int main()
    {
        try
        {
            //1.
            auto p1_ = lexical_cast<int>(std::string(""));
            std::cout << "p1 = " << p1_ << std::endl; //displays 0, which is correct. calls overloaded lexical_cast()
    
            //2.
            auto p2_ = lexical_cast<int>(std::string("1"));
            std::cout << "p2 = " << p2_ << std::endl; //displays 1, which is correct. calls overloaded lexical_cast()
    
            //3.
            std::locale locale_;
            boost::date_time::format_date_parser<boost::gregorian::date, char> parser_("", locale_);
            boost::date_time::special_values_parser<boost::gregorian::date, char> svp_;
            boost::gregorian::date date_ = parser_.parse_date("2014-Dec-17", "%Y-%b-%d", svp_);  //calls boost::lexical_cast(), but I want call to overloaded lexical_cast() instead.
    
            std::cout << date_ << "\n";
        }
        catch(std::exception& e)
        {
            cout << e.what() << "\n";
            return 1;
        }
        return 0;
    }
    

    打印:

    T boost::lexical_cast(const string&) [with T = int; std::string = std::basic_string<char>]
    p1 = 0
    T boost::lexical_cast(const string&) [with T = int; std::string = std::basic_string<char>]
    p2 = 1
    T boost::lexical_cast(const string&) [with T = short int; std::string = std::basic_string<char>]
    T boost::lexical_cast(const string&) [with T = short int; std::string = std::basic_string<char>]
    2014-Dec-17
    

    【讨论】:

    • 已更新以包含一个工作示例 Live On Coliru - 现在添加了 Sfinae(尽管我显然仍然不建议这样做)
    • 很好的答案!我知道你会回答这个问题。保持最佳状态。
    猜你喜欢
    • 2015-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-25
    • 2018-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多