2013-01-21 176 views
2

我有一个函数:模板参数类型

template<class T> 
static string 
format(T ui, T sentinal, char listSeparator) 
{ 
    stringstream s; 
    if (ui == sentinal) 
    { 
     s << "n/a" << listSeparator; 
    } 
    else 
    { 
     s << ui << listSeparator; 
    } 
    return s.str(); 
} 

函数被调用的方法是:

output << format(field1,Backend::NA_Value, csvSeparator); 
output << format(field2,Backend::NA_Value, csvSeparator); 
/// ...etc 

此前field1field2是类型unsigned int的。 决定将这些类型更改为unsigned long long。 但发生编译错误:

std::string format(T,T,char)' : template parameter 'T' is ambiguous 
main.cpp(39) : see declaration of 'format' 
could be 'Juint' 
'unsigned __int64' 

什么是该NA_Value的原因,它被定义为:??

static const Juint NA_Value = (Juint) -1; 
typedef unsigned int Juint 

它不能老是确定型板T?! 从编译器决定关于__int64的地方?

回答

3

这是一个模板类型推导的问题,其中您在函数的签名中出现了多次相同的类型。编译器只是不知道你想要的两种类型中的哪一种,因为在调用中两次出现的是不同的类型

你叫format类似如下(与Juint根据您的typedef被替换):

format(unsigned long long ui, unsigned int sentinal, char listSeparator); 

你改变了前一种说法的类型,所以现在是从第二个不同。在你做这个改变之前,两个参数都是相同的类型。

为了解决这个问题,你有以下几种选择:

  • 制作的模板类型不同。 (see answer by Joachim Pileborg)

  • 当您调用该函数时,通过明确声明它为模板参数来强制指定类型。这将自动转换像你使用它的正常功能(没有类型推演发生在这种情况下)不匹配参数(S):

    output << format<Juint>(field2,Backend::NA_Value, csvSeparator); 
           ^^^^^^^ 
    
    output << format<unsigned long long>(field2,Backend::NA_Value, csvSeparator); 
           ^^^^^^^^^^^^^^^^^^^^ 
    
  • 演员参数传递到其它类型之一。这使得这两个参数是相同的,类型推导会成功:

    output << format(static_cast<Juint>(field2),Backend::NA_Value, csvSeparator); 
           ^^^^^^^^^^^^^^^^^^ 
    
    output << format(field2,static_cast<unsigned long long>(Backend::NA_Value), csvSeparator); 
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
    
  • 变化Juint typedef的,也因此种再次成为同和类型推演也成功。

  • 添加类型特征/ enable_if这将限制模板类型为满足条件的特定类型,但在您的情况下,我不认为这是您想要的。

个人而言,我希望有另一种选择:这将是很好有型扣仅在第一个参数执行,迫使第二个参数要在调用站点自动转换(如“ T但不推导“参数类型”)。但是没有这样的选择。

你的情况最好的选择是让Juint也是同一类型(列表中的第四个选项),或者通过去第一个选项使你的函数“更一般”。正如Joachim Pileborg在一般情况下的答案中所指出的那样,必须小心功能内类型的用法,但在你的情况下应该没有改变功能的身体。

1

Backend::NA_Value的类型不再与field1field2变量相同。一个是unsigned int,另一个是unsigned long long

要么更改Juint typedef以匹配field1field2的类型。如果你选择后者,你会得到其他错误和/或警告有关的比较不匹配的类型

template<class T, class U> 
static string 
format(T ui, U sentinal, char listSeparator) 

当然:或者你也可以添加一个新的模板变量。

+0

对于你的后一种选择,在这种情况下,比较不应该失败;会吗? (无符号整数与无符号长整数)。但是,这个警报当然是重要的。 – leemes

1

编译器错误说明了一切:T是什么意思?它是unsigned long long,如field1所示,或者它是unsigned int,如Backend::NA_Value所示。
编译器无法确定您的意思,因此会产生错误。

可能的解决方案是:

  1. 变化Backend::NA_Valueunsigned long long以及
  2. 明确指定要用于T类型:

    format<unsigned long long>(field1, Backend::NA_Value, csvSeparator); 
    
  3. 更改格式,使得第一第二个参数可以是不同的类型:

    template<class T, class U> 
    static string 
    format(T ui, U sentinal, char listSeparator) 
    { 
        stringstream s; 
        if (ui == sentinal) 
        { 
         s << "n/a" << listSeparator; 
        } 
        else 
        { 
         s << ui << listSeparator; 
        } 
        return s.str(); 
    } 
    

    通过此更改,sentinal可以是与ui相比相等的任何类型。