【发布时间】:2013-07-22 16:28:54
【问题描述】:
我试图在编译时根据一个类型是否在给定范围内公开可用来选择要使用的类型。最好直接上代码:
#include <iostream>
#include <type_traits>
class Logger
{
std::string _p;
public:
Logger(std::string p): _p(p)
{ }
void say(std::string message)
{ std::cout << _p << ' ' << message << std::endl; }
};
struct Log
{
static Logger& log()
{
static Logger _def("Default: ");
return _def;
}
};
// 1.
template <typename P>
struct use_logger
{
static std::size_t test(P*);
static char test(...);
static const bool value = sizeof(test(reinterpret_cast<P*>(0))) == sizeof(std::size_t);
};
class A
{
struct Log
{
static Logger& log()
{
static Logger _def("A: ");
return _def;
}
};
public:
void say()
{
std::cout << "A: " << use_logger<Log>::value << std::endl;
std::conditional<use_logger<Log>::value, Log, ::Log>::type::log().say("From A");
}
};
class B
{
public:
void say()
{
std::cout << "B: " << use_logger<Log>::value << std::endl;
std::conditional<use_logger<Log>::value, Log, ::Log>::type::log().say("From B");
}
};
class C : A
{
public:
void say()
{
std::cout << "C: " << use_logger<Log>::value << std::endl;
//2.
std::conditional<use_logger<Log>::value, Log, ::Log>::type::log().say("From C");
// Log::log().say("From C");
}
};
class D : public A
{
public:
void say()
{
// 2.
std::cout << "D: " << use_logger<Log>::value << std::endl;
std::conditional<use_logger<Log>::value, Log, ::Log>::type::log().say("From D");
// Log::log().say("From C");
}
};
int main(void)
{
{
A i;
i.say();
}
{
B i;
i.say();
}
{
C i;
i.say();
}
{
D i;
i.say();
}
}
我的意图是在A 中有一个类型Log,所以应该使用它而不是全局::Log,并且在B 中没有类型,它应该使用全局@987654327 @。现在这两个工作都不管1. (我不正确的测试,看看类型是否在这个范围内是 private..)
问题出在C 和D,通常情况下 - 如果没有测试,Log::log() 会失败,因为它在 A 中是私有的。但是,如果使用std::conditional<>,则不会出现编译错误,并且输出不正确,因为它以A: 为前缀。那么,我错过了什么(除了不正确的测试 - 我需要以某种方式修复......)?如果没有,那么这种使用std::conditional 公开A 中的私有类型的方法是否合法?
编辑:为了理智,我测试了以下内容:
std::conditional<false, Log, ::Log>::type::log("From C");
std::conditional<false, Log, ::Log>::type::log("From D");
它确实使用了全局::Log,如果是真的,它在某种程度上使用了私有A::Log。
EDIT2:事实上,这似乎是一个更一般的条件,即您可以通过模板间接访问一些内部私有类型,例如:
class F
{
struct Foo
{
void bar() { }
};
};
template <typename T>
struct ExposeInternal
{
typedef T type;
};
int main(void)
{
{
// We've got Foo!
ExposeInternal<F::Foo>::type t;
t.bar();
}
{
// Below fails
F::Foo t;
t.bar();
}
}
编辑 3:好的 - 已经确认,这是一个报告的 GCC 错误,与 std::conditional 无关,尚未在 4.7 或 4.8 中修复。 http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47346
我将暂时保留这个问题。稍后将用上述内容关闭它。
【问题讨论】:
-
请提供一个SSCCE(也许能找到更好的标题?!)
-
@stefan,它是 - 代码应该编译,为简洁起见,我省略了两个标题包含...
-
仍然缺少
#include <string>和结构后的分号。这不是 SSCCE。 -
另外,我没有得到你意想不到的东西。您能否还提供生成的输出和预期/想要的输出?
-
当然需要
<string>,它使用的是std::string。<iostream>或<type_traits>在您的实现中引入<string>这一事实并不意味着它在每个实现中都如此。