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?

4

3 回答 3

3

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

你调用format如下(Juint根据你的替换typedef):

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

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

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

  • 使模板类型不同。(见 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);
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
  • 也改变 的 typedef Juint,使类型再次相同,类型推导也成功。

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

就个人而言,我希望有另一种选择:最好只对第一个参数执行类型推导并强制第二个参数自动在调用站点上强制转换(如“T但不推导”参数类型)。但是没有这样的选择。

在您的情况下,最好的选择是Juint也使用相同的类型(列表中的第 4 个选项),或者通过选择第一个选项使您的函数“更通用”。正如 Joachim Pileborg 的回答一般指出的那样,必须注意函数中类型的用法,但在您的情况下,它应该没问题,而无需更改函数的主体。

于 2013-01-21T12:17:40.100 回答
1

for 的类型Backend::NA_Value不再与field1orfield2变量相同。一个是unsigned int一会儿另一个是一个unsigned long long

要么更改Juinttypedef 以匹配field1and的类型field2。或者您可以添加一个新的模板变量:

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

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

于 2013-01-21T12:17:59.013 回答
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

于 2013-01-21T12:26:16.930 回答