解决基本模板 class 成员的歧义
Resolve ambiguousness of a base template class member
我有一个 classes 的层次结构,它们中的每一个都必须有一个特定的基础 class。比基础 class 提供了 post 日志记录的能力,并接收日志通道的 ctor 名称(基本上是使用日志的 class 的名称)。让我们称之为 class Logable
.
为了让我的 class 继承自那个 Logable
class 几次,我给了它一个模板参数,每个后代都使用它自己作为这个参数。
实际上我使用的是 boost::log 库,但是有一个非常简化的示例,该层次结构具有简单的 LogableImpl
class,它正在替换 boost::log 接收器。
#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_*
宏中指定正确的基成员?
我觉得它可以通过一些模板魔术来完成,但就是想不通。
必须用不支持C++11x特性的MSVC2008来完成
我通过明确指定应该使用哪个 Logable
来使用 c++11 设法做到这一点。由于我们不知道 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 可以理解的内容以使用 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;
}
使用继承来提供对 class 的可登录性的想法很丑陋并且扼杀了想法,但似乎没有 c++11
就没有其他方法了
我有一个 classes 的层次结构,它们中的每一个都必须有一个特定的基础 class。比基础 class 提供了 post 日志记录的能力,并接收日志通道的 ctor 名称(基本上是使用日志的 class 的名称)。让我们称之为 class Logable
.
为了让我的 class 继承自那个 Logable
class 几次,我给了它一个模板参数,每个后代都使用它自己作为这个参数。
实际上我使用的是 boost::log 库,但是有一个非常简化的示例,该层次结构具有简单的 LogableImpl
class,它正在替换 boost::log 接收器。
#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_*
宏中指定正确的基成员?
我觉得它可以通过一些模板魔术来完成,但就是想不通。
必须用不支持C++11x特性的MSVC2008来完成
我通过明确指定应该使用哪个 Logable
来使用 c++11 设法做到这一点。由于我们不知道 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 可以理解的内容以使用 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;
}
使用继承来提供对 class 的可登录性的想法很丑陋并且扼杀了想法,但似乎没有 c++11
就没有其他方法了