【问题标题】:ambiguous template weirdness模棱两可的模板怪异
【发布时间】:2010-11-13 02:26:40
【问题描述】:

我有以下代码(抱歉,代码块很大,但我无法再缩小范围了)

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&lt;...&gt;的类时才会触发,如果我用类似下面的类替换它就没有问题。

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

为什么这个类不会引起歧义,而其他类会?对于具有真正 ::value 的类来说,这两者不是一回事吗? 无论如何,感谢任何关于我做错了什么的提示。

感谢您的回答,我的真正问题(让编译器选择我的第一个专业化)已通过将 struct Foo&lt;X, Base&lt;X&gt;, void&gt; 替换为 struct Foo&lt;X, Base&lt;X&gt;, typename enable_if&lt; Base&lt;X&gt; &gt;::type &gt; 来解决,这似乎按我想要的方式工作。

【问题讨论】:

  • markdown 编辑器不是所见即所得的
  • 我之前修复过,你覆盖了我的更改 :) 如果你愿意,你可以恢复到我的版本(我使用了“10101”按钮,它会自动将这些东西标记为代码,你应该使用它按钮)。
  • Uhjm...我又做了一次,没有阅读您的评论 litb
  • 这是一个众所周知的事实,每个人都会等待 15 秒,看看是否有其他人会先重新格式化问题,然后他们都会同时进行类似但不相同的重新格式化,然后是一半的人假设他们可能做得更好,恢复到第一个编辑的版本......

标签: c++ templates gcc specialization


【解决方案1】:

你的问题的要点是你有:

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&lt;int&gt;)。

根据标准,第 14.5.4 节,如果有更多匹配的特化,则在其中构造一个偏序(如 14.5.5.2 中定义)并使用最特化的一个。但是,在您的情况下,没有一个比另一个更专业。 (简单地说,一个模板比另一个模板更专业,如果你可以用某种类型替换后一个模板的每个类型参数,结果得到前者的签名。另外,如果你有whatever&lt;Y&gt;::type 并且你替换了Y使用Base&lt;X&gt; 你得到whatever&lt;Base&lt;X&gt; &gt;::type 而不是void,即没有执行处理。)

如果您将#2 替换为

template <typename X, typename Y>
struct Foo<X, Y, void > {};                        // #3

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

【讨论】:

  • 这回答了我的问题,但我的核心问题仍然存在。我不知道应该如何在这里完成后续问题,但我会尝试发表评论。有没有办法得到我想要的,在实例化“Foo”时选择#1?就像欺骗编译器认为 #1 可能更专业。
  • +1,其中 +10 更合适。我花了很长时间才写出答案,结果你只用了 29 分钟 :)
  • @keis:问题在于特化是偏序的,在某些情况下,两个元素实际上是没有序的。现在,如果你陈述你真正想要实现的目标(编写一个模板,当用 int 实例化时值为 1,而用 X 实例化时值为 2),那么你可能会得到更好的提示
  • keis,如果您有后续,只需编辑问题。您可以在您已经这样做的一些有希望的答案上发表评论。通常,在您完全满意之前,您不会接受(绿框)答案。
  • dribeas,很抱歉,我为这么简短的回答感到有些羞愧。 :)
【解决方案2】:

我认为您缺少“

template< typename T >
struct myStruct
{};

//OR

template< class T >
struct myStruct
{};

【讨论】:

  • 你为什么要对我投反对票...我在编辑代码之前回复了,此时我的回答很有意义...
  • 因为它没有意义现在。如果您不想通过编辑来回答新问题,请完全删除您的答案。
  • 而且无论如何,丢失的
【解决方案3】:

你是不是错过了一个

<

符号?

【讨论】:

  • 在网站的 HTML 解析器中丢失,希望我现在修复它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-05-10
  • 2015-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多