模板专业化不明确

时间:2011-06-18 09:03:04

标签: c++ templates template-meta-programming

又一个模板问题!我正在尝试获取一个模板方法,如果它有一个运算符的重载<<。 我几乎都在工作,并实现了一个enable_if,以使g ++为每种类型的对象选择预期的特化。

事情是,使用非重载对象,它工作得很好。但是对于一个超载的,我的两个专业都是g ++的合理选择,而不是编译它输出一个模糊的重载错误。

以下是代码:

template<typename T>
  static void   Print(Stream& out, T& param, typename enable_if<CanPrint<T>::value>::type = 0)
  {
    out << param;
  }

  template<typename T>
  static void   Print(Stream& out, T& param)
  {
    out << "/!\\" << typeid(param).name() << " does not have any overload for <<.\n";
  }

我理解为什么这样的事情是模棱两可的。然而,我想不出一种方法可以让它变得更加明显......我如何让编译器明白第二次重载只有在第一次不能被选中时才会被选中?

3 个答案:

答案 0 :(得分:8)

你会得到歧义,因为在这两种情况下你都有一个函数,它接受一个流,后跟你的类型T作为前两个参数。这虽然有效:

#include <iostream>
#include <boost/utility/enable_if.hpp>
#include <typeinfo>

template <class T>
struct CanPrint { enum { value = 0 }; };

template <>
struct CanPrint<int> { enum { value = 1 }; };

template<typename T>
typename boost::enable_if<CanPrint<T>, void>::type 
    Print(std::ostream& out, T& param)
{
    out << param << std::endl;
}

template<typename T>
typename boost::disable_if<CanPrint<T>, void>::type 
    Print(std::ostream& out, T& param)
{
    out << "/!\\" << typeid(param).name() << " does not have any overload for <<.\n";
}

int main()
{
    int i = 1;
    double d = 2;

    Print(std::cout, i);
    Print(std::cout, d);
}

答案 1 :(得分:1)

歧义是因为默认参数值。

调用Print(stream, whatever)可以解析为带有默认第三个参数的第一个版本或没有第三个参数的第二个版本。

删除默认值,编译器会理解。否则,他们两个都可以永远选择。

答案 2 :(得分:1)

我认为这与模板无关。以这种方式重载的自由函数会产生同样的错误。

检查这个简单的代码示例,它类似于您在模板示例中所做的事情:

void doSomething(int i, int j, int k );
void doSomething(int i, int j, int k = 10);


void doSomething(int i, int j, int k)
{

}

void doSomething(int i, int j)
{

}


int main()
{
    doSomething(10,20);
    return 0;
}

错误是:

prog.cpp:18: error: call of overloaded ‘doSomething(int, int)’ is ambiguous
prog.cpp:5: note: candidates are: void doSomething(int, int, int)
prog.cpp:10: note:                 void doSomething(int, int)

显然,你不能仅仅根据默认参数重载这些函数。