我有一些我不理解的编译器行为-在VisualC ++和g ++上有所不同(对于任何一个编译器)。我将用英语对其进行描述,但仅看下面的代码也许会更容易。
它与具有成员类模板和成员函数模板的类模板有关。我正在尝试同时
我发现,如果我同时执行 #1(显式专门化外部类模板)或#2(显式专门化成员模板),则使用这两个编译器,一切都可以正常编译(且实例化均符合预期)。
但是如果我尝试同时执行#1和#2(我相信以正确的顺序声明),我会发现
这是外部类模板的主要定义。在以下所有情况下都相同:
// Class template with a member class template and a member function template
template <int I>
struct OuterClass
{
template <int J> struct InnerClass {};
template <int J> static void InnerFunc() {}
};
这里仅执行#1(专门针对外部类模板)。这样可以很好地进行编译,并且实例化符合预期。
// Explicit specialization of outer class template,
// leaving member templates unspecialized.
template <>
struct OuterClass<1>
{
template <int J> struct InnerClass {};
template <int J> static void InnerFunc() {}
};
这里仅执行#2(显式专门化成员模板)。这样可以很好地进行编译,并且实例化符合预期。
// Explicit specialization of inner templates for
// an explicit specialization of outer class template
template <> template <> struct OuterClass<1>::InnerClass<1> {};
template <> template <> void OuterClass<1>::InnerFunc<1>() {}
这里尝试同时执行#1和#2-只是将之前的两个代码片段粘贴在一起:
// Explicit specialization of outer class template,
// leaving member templates unspecialized.
template <>
struct OuterClass<1>
{
template <int J> struct InnerClass {};
template <int J> static void InnerFunc() {}
};
// Explicit specialization of inner templates for
// an explicit specialization of outer class template
template <> template <> struct OuterClass<1>::InnerClass<1> {}; // Line A
template <> template <> void OuterClass<1>::InnerFunc<1>() {} // Line B
g ++可以很好地编译“ A行”(实例化与预期的一样)。但是g ++给出了B行的编译器错误:“模板模板列表过多”。
VC ++给出了“ A行”和“ B行”的编译器错误(太杂乱,在此不胜枚举)。
同样,当在外部类模板的显式专门化之后没有出现“ A行”和“ B行”时,对于这两个编译器来说,它们都可以很好地编译。
据我了解,一切都应该编译良好。那么谁是正确的-我,g ++还是VC ++?更重要的是,为什么呢?
请理解这不是“如何完成X”问题,这是“我想完全了解C ++”问题。如果您花时间仔细阅读并仔细考虑,您将非常感谢...我希望我尽可能将其精简。
答案 0 :(得分:2)
我在这个问题上花费了很多荒谬的时间,我想我已经弄明白了-通过“搞清楚”,我的意思是我确切知道在我尝试过的两个编译器(MSVC和g ++),以及每个编译器使用什么语法。这一切都很难看,但是可以预测并且可以重复-我这里没有显示很多示例代码,我可以从中推论出结果。为了清楚起见,避免我感到沮丧,这里的描述不是我的理论,而是在各种示例案例中观察到编译器的行为。
高级别:
我在这里给出的详细描述可能太简短了,以至于普通读者无法理解,但是我还是会尝试的。
这是一些示例代码,显示了在定义带有特定专业化链的嵌套类模板时,“ template <>”必须出现多少次。这可以在MSVC和g ++上进行编译(使用条件编译)。该代码不涉及嵌套的 function 模板。
#include <boost\predef.h> // For conditional compilation
// Nested class templates, 3 deep.
template <int I1> struct T1
{
template <int I2> struct T2
{
template <int I3> struct T3 {};
};
};
// Specialization of the third level of class template.
// "template<>" appears three times here for both MSVC and g++ -
// in this case the rules for both compilers both yield 3.
// Note this class template specialization nests another 2 levels of class templates.
template <> template <> template<> struct T1<1>::T2<1>::T3<1>
{
template <int I4> struct T4
{
template <int I5> struct T5 {};
};
};
// Specialize the class template contained in the class template specialization above.
// In this case, the number of times "template<>" must appear differs between MSVC and g++,
// so conditional compilation is used.
#if BOOST_COMP_GNUC
// According to the rule described for g++, "template<>" must appear 4 times:
// (Overall specialization level of 5) - (1 covering specialization which is T1<1>::T2<1>::T3<1>) = 4
template <> template<> template<> template<> struct T1<1>::T2<1>::T3<1>::T4<1>::T5<1>
#elif BOOST_COMP_MSVC
// MSVC uses the last hop specialization rule, so "template<>" must appear 2 times -
// because the closest covering specialization, T1<1>::T2<1>::T3<1>, is two hops back.
template <> template<> struct T1<1>::T2<1>::T3<1>::T4<1>::T5<1>
#else
#error Unsupported compiler!
#endif
{
//...
}