c++ - 如何简化boost::static_vistor的派生类

标签 c++ boost

template<typename T>
class ClassVariantVisitor : public boost::static_visitor<T>
{
public:
  T operator()(int& i) const {
    try
      {
        return boost::lexical_cast<T>(i);
      } 
    catch ( boost::bad_lexical_cast& e)
      {
        throw e.what();
      }
  }

  T operator()(double& d) const {
    try
      {
        return boost::lexical_cast<T>(d);
      } 
    catch ( boost::bad_lexical_cast& e)
      {
        throw e.what();
      }
  }

  // ...
};

如您所见,对于每种不同的类型,operator() 的实现代码完全相同。有没有一种实用的方法可以简化代码?

谢谢

//根据评论更新//

template<typename T>
class ClassVariantVisitor : public boost::static_visitor<T>
{
public:
  T operator()(T& i) const {
    try
      {
        return boost::lexical_cast<T>(i);
      } 
    catch ( boost::bad_lexical_cast& e)
      {
        throw e.what();
      }
  }
};

然后编译器(G++)将生成大量的 errors

/////根据 iammilind 的评论更新了 2

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <boost/variant.hpp>
#include <boost/lexical_cast.hpp>

using namespace std;

typedef boost::variant<int, double, string> VarIntDoubleString;

// T is the result_type
template<typename T>
class ClassVariantVisitor : public boost::static_visitor<T>
{
public:
  template<typename U>
  T operator()(U& i) const {
    try
      {
        return boost::lexical_cast<T>(i);
      } 
    catch ( boost::bad_lexical_cast& e)
      {
        throw e.what();
      }
  }
};

int main(void)
{
  map<string, VarIntDoubleString> mapValuesThree;

  // store & retrieve char
  mapValuesThree["char_fieldI"] = VarIntDoubleString('c');
  char fieldI = boost::apply_visitor(ClassVariantVisitor<char>(), mapValuesThree["char_fieldI"]);
  cout << "fieldI: " << fieldI << endl;
}


~/Documents/C++/boost $ g++ -o p192f4 p192f4.cpp -Wall
~/Documents/C++/boost $ ./p192f4
terminate called after throwing an instance of 'char const*'
aborted
~/Documents/C++/boost $ g++ --version
g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2

致 iammilind: 正如您所看到的,编译器在编译期间不会生成任何错误或警告。

//根据 Konstantin Oznobihin 的评论更新了 3

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <boost/variant.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/contains.hpp>
#include <boost/utility/enable_if.hpp>

using namespace std;
template<typename T>
class ClassVariantVisitor : public boost::static_visitor<T>
{
public:
  typedef boost::mpl::vector<int, double, string> VarIntDoubleString;

  template <class U>
  typename boost::enable_if<
    typename boost::mpl::contains<VarIntDoubleString, U>::type, T>::type operator()(U &v) const 
  {
    try
      {
        return boost::lexical_cast<T>(v);
      } 
    catch ( boost::bad_lexical_cast& e)
      {
        throw e.what();
      }
  }
};

int main(void)
{
  map<string, ClassVariantVisitor::VarIntDoubleString> mapValuesThree;

  // store & retrieve double
  mapValuesThree["double_fieldJ"] = ClassVariantVisitor<double>::VarIntDoubleString(2.3456);
  double fieldJ = boost::apply_visitor(ClassVariantVisitor<double>(), mapValuesThree["double_fieldJ"]);
  cout << "fieldJ: " << fieldJ << endl;

}

我对 boost::mpl 不了解,无法使其工作。请引用errors 您可以告诉我如何更正代码,以便我使用您的想法并使其发挥作用。 谢谢

最佳答案

按照iammilind的建议使用模板化的operator(),但使用boost::mpl过滤类型:


template<typename T>
class ClassVariantVisitor : public boost::static_visitor<T>
{
public:
  typedef boost::mpl::vector<int, double> source_types;

  template <class U>
  typename boost::enable_if<
    typename boost::mpl::contains<source_types, U>::type,
    T
  >::type operator()(U &v) const {
    try
      {
        return boost::lexical_cast<T>(v);
      } 
    catch ( boost::bad_lexical_cast& e)
      {
        throw e.what();
      }
};

更新: 如果您有 boost::variant,您可以使用它的嵌套类型序列 types 而不是 boost::mpl::vector,并且您不需要在 ClassVariantVisitor 中定义变体,这里是基于您的代码的更新解决方案:


#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <boost/variant.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/contains.hpp>
#include <boost/utility/enable_if.hpp>

using namespace std;

typedef boost::variant<int, double, string> VarIntDoubleString;

template<typename T>
class ClassVariantVisitor : public boost::static_visitor<T>
{
public:
  template <class U>
  typename boost::enable_if<
    typename boost::mpl::contains<VarIntDoubleString::types, U>::type, T>::type operator()(U &v) const 
  {
    try
      {
        return boost::lexical_cast<T>(v);
      } 
    catch ( boost::bad_lexical_cast& e)
      {
        throw e.what();
      }
  }
};

int main(void)
{
  map<string, VarIntDoubleString> mapValuesThree;

  // store & retrieve double
  mapValuesThree["double_fieldJ"] = VarIntDoubleString(2.3456);
  double fieldJ = boost::apply_visitor(ClassVariantVisitor<double>(), mapValuesThree["double_fieldJ"]);
  cout << "fieldJ: " << fieldJ << endl;
}

关于c++ - 如何简化boost::static_vistor的派生类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8937188/

相关文章:

c++ - 如何使用 boost::process 向子进程发送 SIGTERM

c++ - boost::flyweight 不适用于类

c++ - 使用带有 shared_ptr 键的 unordered_set

c++ - 为什么 MFC DoModal 返回 -1 ? -1 是什么意思?

c++ - 这三种调用方法的语法形式有什么区别?

c++ - boost::iostream readline 在 4096 字节后停止

python - Boost.Python 并导入一个 dll, "The specified module could not be found"

c++ - QComboBox 信号未触发

c++ - 错误 C4018 与 vector 大小 () 在 c++

c++ - boost::qi::parse 似乎会导致编译错误