【发布时间】:2013-03-18 09:42:13
【问题描述】:
我正在尝试使用条件成员创建一个结构,这意味着不同的成员仅存在于特定的专业化中。但是,我希望这些课程尽可能快。我尝试了三种不同的方式:
方式一:
template<typename T, bool with_int = false>
struct foo
{
template<typename... Args>
foo(Args&&... args) : m_t(forward<Args>(args)...)
{}
T m_t;
}
template<typename T>
struct foo<T, true>
{
template<typename... Args>
foo(Args&&... args) : m_t(forward<Args>(args)...), m_id(0)
{}
T m_t;
int m_id;
};
- 缺点:每个专业都有重复的代码。
方式 2:
template<typename T, bool with_int = false>
struct foo
{
template<typename... Args>
foo(Args&&... args) : m_t(forward<Args>(args)...)
{}
virtual ~foo() {}
T m_t;
}
template<typename T>
struct foo<T, false> : public foo<T>
{
using foo<T>::foo;
int m_id = 0;
};
- 优点:代码少。
- 缺点:使用 vtables/inheritance/etc:更多时间用于构建或访问成员?但是,在其他方面,我不会假装使用“引用”来访问基类。这种方法的真正优点或缺点是什么?
方式 3
using nil_type = void*;
using zero_type = nil_type[0];
template<typename T, bool with_int = false>
struct foo
{
template<typename... Args, typename = typename enable_if<with_int>::type>
foo(Args&&... args) : m_t(forward<Args>(args)...), m_int(0)
{}
template<typename... Args, typename = typename enable_if<!with_int>::type>
foo(Args&&... args) : m_t(forward<Args>(args)...)
{}
T m__t;
typename conditional<with_int, int, zero_type>::type m_int;
};
- Ventages:编写一次代码;当
with_int为false时,m_int字段的大小为 0(几乎使用 gcc 4.7.2)。 - 优点:更多地使用模板(降低可读性)并且我不确定编译器如何处理大小为 0 的成员。我确实不知道大小为 0 的字段在多大程度上是危险的或有意义的。重复构造函数,但也许这是可以避免的。
什么是最好的方法或方法?
【问题讨论】:
-
OT,但我很确定包含双下划线的名称是为编译器保留的,因此您应该使用
m_int和m_t。 -
我认为只有成员开始有双下划线,但不包含它。
-
不行,看答案here:
Each name that contains a double underscore (_ _) or begins with an underscore followed by an uppercase letter (2.11) is reserved to the implementation for any use. -
请注意,您不能拥有大小为 0 的成员,编译器仍会为其分配非零大小。 &Var1 == &Var2 当且仅当 Var1 和 Var2 是同一个变量。任何大小为 0 的变量都会违反这一点。
-
那么,
sizeof撒谎?sizeof说我zero_type的大小为 0,foo<int, false>的大小为 4,foo<int, true>的大小为 8。与struct { char m[0] };相同:sizeof返回 0。
标签: c++ c++11 conditional-compilation