解决基本模板类成员的模糊性

时间:2015-05-22 13:24:15

标签: c++ templates ambiguity boost-log

我有一个类层次结构,每个类都必须有一个特定的基类。比基类提供发布日志记录的能力并接受日志通道的ctor名称(基本上是使用日志的类的名称)。让我们称这个班为Logable

为了允许我的类多次从该Logable类继承,我给它一个模板参数,每个后代都将自己用作此参数。

实际上我正在使用boost :: log库,但是有一个非常简单的示例,所述层次结构使用简单的LogableImpl类,它正在替换boost :: log sink。

#include <iostream>
#include <string>

// macro for logging in a boost::log style
#define LOG_DEBUG this->_loggerObj.logStream("debug")
#define LOG_INFO  this->_loggerObj.logStream("info")
#define LOG_WARN  this->_loggerObj.logStream("warning")
#define LOG_ERROR this->_loggerObj.logStream("error")


class LogableImpl
{
private:
   std::string _channelName;
public:
   LogableImpl(const std::string & channelName): _channelName(channelName) {}

   std::ostream & logStream(const std::string & severetyLevel)
   {
      std::cout << _channelName << " " << severetyLevel;
      return std::cout;
   }
};


template <class Descendant>
class Logable
{
protected:
   Logable(const std::string & channelName): _loggerObj(channelName) {}
   LogableImpl _loggerObj;
};


class Base: private Logable<Base>
{
public:
   Base()
      : Logable<Base>("Base")
   {}

   void someMethod()
   {
      LOG_INFO << "some method is called" << std::endl;
      LOG_ERROR << "an error happened" << std::endl;
   }
};


class Derived: public Base, private Logable<Derived>
{
public:
   Derived()
      : Logable<Derived>("Derived")
   {}

   void someAnotherMethod()
   {
      LOG_INFO << "another method is called" << std::endl;
      LOG_ERROR << "another error is happened" << std::endl;
   }
};


int main()
{
   Base b;
   Derived d;
   b.someMethod();
   d.someMethod();

   return 0;
}

显然,我在使用MSVC 2008进行此源代码编译尝试时遇到错误

error C2385: ambiguous access of '_loggerObj'
1>        could be the '_loggerObj' in base 'Logable<Base>'
1>        or could be the '_loggerObj' in base 'Logable<Derived>'
1>d:\cpp\visualstudio\tests\workbench\test\main.cpp(55) : error C2248: 'Logable<Descendant>::_loggerObj' : cannot access inaccessible member declared in class 'Logable<Descendant>'
1>        with
1>        [
1>            Descendant=Base
1>        ]
1>        d:\cpp\visualstudio\tests\workbench\test\main.cpp(29) : see declaration of 'Logable<Descendant>::_loggerObj'
1>        with
1>        [
1>            Descendant=Base
1>        ]
1>d:\cpp\visualstudio\tests\workbench\test\main.cpp(56) : error C2385: ambiguous access of '_loggerObj'
1>        could be the '_loggerObj' in base 'Logable<Base>'
1>        or could be the '_loggerObj' in base 'Logable<Derived>'
1>d:\prog\cpp\visualstudio\tests\workbench\boost_test\main.cpp(56) : error C2248: 'Logable<Descendant>::_loggerObj' : cannot access inaccessible member declared in class 'Logable<Descendant>'
1>        with
1>        [
1>            Descendant=Base
1>        ]
1>        d:\cpp\visualstudio\tests\workbench\test\main.cpp(29) : see declaration of 'Logable<Descendant>::_loggerObj'
1>        with
1>        [
1>            Descendant=Base
1>        ]
1>Build log was saved at "file://d:\cpp\visualStudio\tests\workbench\test\Debug\BuildLog.htm"
1>boost_test - 4 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

如何指定在LOG_*宏中使用的正确的基本成员? 我觉得它可以通过一些模板魔法来完成,但只是无法弄明白。

必须使用MSVC2008,它不支持C ++ 11x功能

2 个答案:

答案 0 :(得分:1)

我设法使用c ++ 11通过明确指定应该使用哪个Logable来做到这一点。由于我们不知道this的类型,因此我使用decltype

#define LOGABLE_TYPE typename std::remove_reference<decltype(*this)>::type
#define LOG_DEBUG this->Logable<LOGABLE_TYPE>::_loggerObj.logStream("debug")
#define LOG_INFO  this->Logable<LOGABLE_TYPE>::_loggerObj.logStream("info")
#define LOG_WARN  this->Logable<LOGABLE_TYPE>::_loggerObj.logStream("warning")
#define LOG_ERROR this->Logable<LOGABLE_TYPE>::_loggerObj.logStream("error")

请在此处查看完整代码:http://ideone.com/1D5jrj

答案 1 :(得分:1)

不幸的是,我找不到将decltype替换为msvc 2008可以理解使用Petr的答案的方法。即使boost::typeof也不合适(只要我正确使用它)

所以我通过添加using案例和宏

来提供解决方案
#include <iostream>
#include <string>

#define USE_APPROPRIATE_LOGGER(classname) using Logable<classname>::_loggerObj
#define LOG_DEBUG _loggerObj.logStream("debug")
#define LOG_INFO  _loggerObj.logStream("info")
#define LOG_WARN  _loggerObj.logStream("warning")
#define LOG_ERROR _loggerObj.logStream("error")

class LogableImpl
{
private:
   std::string _channelName;
public:
   LogableImpl(const std::string & channelName): _channelName(channelName) {}

   std::ostream & logStream(const std::string & severetyLevel)
   {
      std::cout << _channelName << " " << severetyLevel << " ";
      return std::cout;
   }
};


template <class Descendant>
class Logable
{
protected:
   Logable(const std::string & channelName): _loggerObj(channelName) {}
   LogableImpl _loggerObj;
};

class Base: private Logable<Base>
{
   USE_APPROPRIATE_LOGGER(Base);
public:
   Base()
      : Logable<Base>("Base")
   {}

   void someMethod()
   {
      LOG_INFO << "some method is called" << std::endl;
      LOG_ERROR << "an error happened" << std::endl;
   }
};

class Derived: public Base, private Logable<Derived>
{
   USE_APPROPRIATE_LOGGER(Derived);
public:
   Derived()
      : Logable<Derived>("Derived")
   {}

   void someAnotherMethod()
   {
      LOG_INFO << "another method is called" << std::endl;
      LOG_ERROR << "another error is happened" << std::endl;
   }
};


int main()
{
   Base b;
   Derived d;
   b.someMethod();
   std::cout << std::endl;
   d.someAnotherMethod();

   return 0;
}

它的丑陋和杀死使用继承为类提供可记录性的想法,但似乎没有其他方法没有c ++ 11