模板参数类型

时间:2013-01-21 12:15:02

标签: c++ templates parameters

我有一个功能:

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 个答案:

答案 0 :(得分:3)

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

您可以按以下方式致电format(根据您的Juint替换typedef):

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

您更改了前一个参数的类型,现在它与第二个不同。在进行此更改之前,两个参数都具有相同的类型。

要解决此问题,您有以下选择:

  • 使模板类型不同。 (see answer by Joachim Pileborg)

  • 在调用函数时,通过显式将其指定为模板参数来强制使用特定类型。这将自动转换非匹配参数,就像您习惯使用普通函数一样(在这种情况下不会发生类型推导):

    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,它会将模板类型限制为满足条件的特定类型,但在您的情况下,我认为这不是您想要的。

就个人而言,我希望还有另一个选择:让类型推导仅对第一个参数执行并强制第二个参数自动在调用网站上投射(如“{{1}但不要推断“参数类型”。但是没有这样的选择。

在你的情况下,最好的选择是使同一类型T(列表中的第4个选项)或通过选择第一个选项使你的功能“更通用”。正如Joachim Pileborg在一般情况下的答案中所指出的那样,必须注意函数中类型的用法,但在你的情况下,在不改变函数体的情况下应该没有问题。

答案 1 :(得分: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)

当然,如果您执行后者,您将在比较中收到有关不匹配类型的其他错误和/或警告。

答案 2 :(得分:1)

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

可能的解决方案是:

  1. 同时将Backend::NA_Value更改为unsigned 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相比可以相等的任何类型。