重载的boost :: lexical_cast函数

时间:2014-12-17 14:32:42

标签: c++ c++11 boost

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

我的程序有效,在前2个案例中调用了重载的lexical_cast(),因为这两个调用都是在本地进行的。在第三种情况下,调用父函数boost :: lexical_cast(),因为对boost :: lexical_cast()的调用是通过parse_date()进行的。

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

有什么办法,我可以编写这样一个全局lexical_cast()函数处理程序吗?

另外,请建议我们如何使这个全局处理程序自定义,以便只能为选定的少数POD&无论何时指定数据类型,都会提升数据类型。

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

1 个答案:

答案 0 :(得分:1)

你的节目&#34;工作&#34;但是与未定义的行为调情。

在不同的翻译单元中重新定义完全相同的符号的竞争定义在技术上违反了单一定义规则。 你可以在这里侥幸成功,因为它只是关于功能实例,而且一次只能看到/选择一个。但是,

  • 这并不能使它更有效地超载&#34;过载&#34;图书馆特色。
  • 这有能力默默地改变内部(隐形?)所包含的其他代码的行为取决于lexical_cast。尤其是沉默&#34;后退&#34;默认的空字符串构造值是库用户可能无法很好地处理的行为更改。你基本上违反了其他客户对boost lexical_cast
  • 的合同

唯一的结构模式是邀请用户过载&#34;过载&#34;在库名称空间内,当在 Designed-for 扩展点(在TMP中的a.k.a.定制点)扩展库时。通常这需要

  • 课程的专业化(如std::hash<>boost::hash<>boost::spirit::traits::is_container<>BOOST_FUSION_ADAPT_STRUCT()等。)
  • 添加对用户定义类型的参数(例如std::swap,可能std::iter_swap,还有boost::serialization::serialize)重载的函数的重载。重要在这种情况下,通常命名空间入侵不是首选,实际上不是必需的,因为重载可以在与用户定义类型相关联的命名空间中声明(例如std::swap(mypgrogram::typeA&, mypgrogram::typeA&)甚至{{ 1}}可以在命名空间std::swap(boost::optional<mypgrogram::typeA>&, boost::optional<mypgrogram::typeA>&)中完全定义,然后编译器可以解析正确的重载,可选地在两阶段查找中,使用参数依赖查找(ADL)

因此,除非Boost Lexicalcast记录了您使用的 自定义点 ,否则您无法可靠地将其用于其他模块(除了如果你能以某种方式保证所有调用都能看到你的定义)。在这种情况下,只需更改Boost Lexicalcast就可以了。毕竟这正是你打算做的事情。

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

::mypgrogram

<强> Live On Coliru

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

打印:

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