重载提升::lexical_cast函数

Overloaded boost::lexical_cast function

本文关键字:cast 函数 lexical 重载      更新时间:2023-10-16

我希望编写自己的转换函数并重用boost::lexical_cast((;因此我重载了boost::lexical_cast((函数。毕竟,将 boost::conversion::try_lexical_convert(( 添加到库中也是出于同样的目的。

我的程序可以工作,重载 lexical_cast(( 在前 2 种情况下被调用,因为这两个调用都是在本地进行的。在第三种情况下,父函数 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;
}

你的程序"工作",但与未定义的行为调情。

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

  • 这不会使"重载"库功能更有效。
  • 这能够静默地更改包含在内部(不可见的?(依赖于lexical_cast的其他代码的行为。特别是对空字符串的默认构造值的静默"回退"是一种行为更改,库用户可能无法很好地应对。你基本上违反了其他客户与提升lexical_cast的合同

只有邀请用户在库命名空间内"重载"的结构模式,即在设计用于扩展点(TMP 中的自定义点(扩展库时。这通常需要

  • 类的专业化(如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&)甚至std::swap(boost::optional<mypgrogram::typeA>&, boost::optional<mypgrogram::typeA>&)都可以在命名空间 ::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)

住在科里鲁

#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