解决基模板类成员的模糊性
Resolve ambiguousness of a base template class member
我有一个类的层次结构,每个类都必须有一个特定的基类。基类提供了发布日志记录的能力,并接受日志通道的tor名称(基本上是使用log的类的名称)。我们称这个类为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:cppvisualstudiotestsworkbenchtestmain.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:cppvisualstudiotestsworkbenchtestmain.cpp(29) : see declaration of 'Logable<Descendant>::_loggerObj'
1> with
1> [
1> Descendant=Base
1> ]
1>d:cppvisualstudiotestsworkbenchtestmain.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:progcppvisualstudiotestsworkbenchboost_testmain.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:cppvisualstudiotestsworkbenchtestmain.cpp(29) : see declaration of 'Logable<Descendant>::_loggerObj'
1> with
1> [
1> Descendant=Base
1> ]
1>Build log was saved at "file://d:cppvisualStudiotestsworkbenchtestDebugBuildLog.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的特性
我使用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
不幸的是,我无法找到一种方法将decltype
替换为msvc 2008可以理解的东西,以使用peter的答案。即使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
相关文章:
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 避免易失性和非易失性成员函数的代码重复
- 班级成员可见性C++
- 自动模板参数、数据成员和恒常性
- 带boost的过载模糊性:可选,解决方法
- C++模板 - 实例之间的通用操作和成员可见性
- 成员函数声明签名中的类成员可见性
- C++中的构造函数调用模糊性
- 更改类模板成员可见性
- 运算符[]模糊性解析
- C++异常继承模糊性
- Visual Studio在添加if语句后显示C++模糊性错误
- 类中的内部成员可见性
- 非成员函数中的隐式参数转换模糊性使用std::函数重载
- c++中的函数重载模糊性
- 静态多态性中的模糊性
- 涉及模板化转换操作符和隐式复制构造函数的模糊性
- 泛型类型初始化的模糊性
- 解决基模板类成员的模糊性
- 模板函数调用模糊性错误