暧昧的模板怪异

时间:2009-07-22 17:17:13

标签: c++ templates gcc specialization

我有以下代码(对于大代码块很抱歉,但我不能再缩小它了)

template <bool B>
struct enable_if_c {
      typedef void type;
};

template <>
struct enable_if_c<false> {};

template <class Cond>
struct enable_if : public enable_if_c<Cond::value> {};

template <typename X>
struct Base { enum { value = 1 }; };

template <typename X, typename Y=Base<X>, typename Z=void>
struct Foo;

template <typename X>
struct Foo<X, Base<X>, void> { enum { value = 0 }; };

template <typename X, typename Y>
struct Foo<X, Y, typename enable_if<Y>::type > { enum { value = 1 }; };

int main(int, char**) {
        Foo<int> foo;
}

但是无法使用gcc(v4.3)和

进行编译
foo.cc: In function ‘int main(int, char**)’:
foo.cc:33: error: ambiguous class template instantiation for ‘struct Foo<int, Base<int>, void>’
foo.cc:24: error: candidates are: struct Foo<X, Base<X>, void>
foo.cc:27: error:                 struct Foo<X, Y, typename enable_if<Y>::type>
foo.cc:33: error: aggregate ‘Foo<int, Base<int>, void> foo’ has incomplete type and cannot be defined
好的,所以这是不明确的。但我并不认为这是一个问题,因为在使用专业化时,它几乎总是会有些含糊不清。但是,只有在使用enable_if<...>的类时才会触发此错误,如果我将其替换为类似以下的类则没有问题。

template <typename X, typename Y>
struct Foo<X, Y, void > { enum { value = 2 }; };

为什么这个课程不会引起歧义,而其他人呢?具有true :: value的类不是两个相同的东西吗? 无论如何,任何关于我做错的提示都会受到赞赏。

感谢您的回答,我的真正问题(让编译器选择我的第一个专业化)通过将struct Foo<X, Base<X>, void>替换为struct Foo<X, Base<X>, typename enable_if< Base<X> >::type >来解决,这似乎是有效的我想要。

3 个答案:

答案 0 :(得分:12)

你的问题的主旨是:

template <typename X, typename Y, typename Z>
struct Foo {};

template <typename X>
struct Foo<X, Base<X>, void> {};                   // #1

template <typename X, typename Y>
struct Foo<X, Y, typename whatever<Y>::type> {};   // #2

并且您正在尝试将其与

相匹配
Foo<int, Base<int>, void>

显然,两个专业都匹配(第一个与X = int匹配,第二个与X = int, Y = Base<int>匹配。

根据标准第14.5.4节,如果有更多匹配的特化,则构造它们之间的部分排序(如14.5.5.2中所定义),并使用最专业的一个。然而,在你的情况下,没有一个比另一个更专业。 (简单地说,一个模板比另一个模板更专业,如果你可以用某种类型替换后一个模板的每个类型参数,结果得到前者的签名。另外,如果你有whatever<Y>::type并且你替换{ {1}}使用Y Base<X>而不是whatever<Base<X> >::type,即没有执行处理。)

如果用

替换void
#2

然后候选集再次包含两个模板,但是,#1比#3更专业,因此被选中。

答案 1 :(得分:-1)

你错过了

<

符号?

答案 2 :(得分:-2)

我认为你错过了一个'&lt;',模板应该是这样的:

template< typename T >
struct myStruct
{};

//OR

template< class T >
struct myStruct
{};