c++ - 重载 boost::lexical_cast 函数

标签 c++ c++11 boost

我希望编写自己的转换函数并重用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() 时,我的重载函数都会被调用。

有什么办法,我可以写这样一个global lexical_cast() function handler吗?

此外,请建议我们如何定制全局处理程序,使其只能在指定的少数 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的其他代码的行为。 .特别是对空字符串的默认构造值的静默“回退”是库用户可能无法很好应对的行为变化。你基本上违反了其他客户与 boost lexical_cast 的契约(Contract)

只有结构模式邀请用户在库命名空间内“重载”,即在designed-for 扩展点(也就是 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)

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

关于c++ - 重载 boost::lexical_cast 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27527913/

相关文章:

C++:获取 std::bind 产生的参数

c++ - 在 Cygwin 上编译 Boost, header 在 32/64 位上不一致

c++ - 使用 boost::regex 获取子匹配结果

c++ - 如何计算文件中的零和一?

c++ - 如何通过类型和非类型模板参数重载模板类?

c++ - MFC 在标签之间提取 CString

c++ - posix timer_create() 函数在 linux 上导致内存泄漏

c++ - 不使用适用于 C++ 的 MySql Connector 建立 MySQL 连接

c++ - 基本 RValue 方法返回

c++ - 不支持 boost::filesystem::create_symlink