提问者:小点点

为什么模板参数的no delivery只作为返回类型使用?


如果我没有在函数参数列表中使用tempate参数(type)->; 只作为返回类型,则没有扣减:

template <typename T>
T zero() { return 0; }

int main()
{
    int x = zero();
}

给予:

a.cpp:15:18: error: no matching function for call to ‘zero()’
     int x = zero();
                  ^
a.cpp:11:3: note: candidate: ‘template<class T> T zero()’
 T zero() { return 0; }
   ^~~~
a.cpp:11:3: note:   template argument deduction/substitution failed:
a.cpp:15:18: note:   couldn't deduce template parameter ‘T’
     int x = zero();

编译的唯一方法是在尖括号中指定模板类型:

template <typename T>
T zero() { return 0; }

int main()
{
    int x = zero<int>();
}

>

  • 所以我的问题是,为什么G++可以从模板函数的参数列表推导出类型,而不能从返回类型(编译main时也为编译器所知,所以知道类型)推导出来。

    当模板函数在其参数列表中使用模板类型时,在尖括号中为模板函数提供类型是任意的(因为推论)? 因此,作为一个好的实践,我是否应该总是用花括号提供类型,不管函数是如何声明的?

    第二个问题可读性不高。 用简单的话来说->; 我是否应该每次都使用foo(arg,...)(提供类型),无论函数声明如何? 即使它可以被编译器推演,但我会提供类型无论如何好的实践?


  • 共3个答案

    匿名用户

    通常,不可能根据函数的返回类型推导函数。 但是如果您使用自动类型转换C++特性,那么您就可以实现您所需要的:

    template <typename T>
    T zero() { return 1; }
    
    template <>
    float zero<float>() { return 3.0f; }
    
    struct Zero
    {
        template<typename T>
        operator T()
        {
            return zero<T>();
        }
    };
    
    int main()
    {
        int x = Zero();
        float y = Zero();
        return x + y;
    }
    

    首先创建临时对象Zero(),在分配过程中使用转换运算符对Zero模板函数执行正确的专门化。

    匿名用户

    所以我的问题是,为什么g++可以从模板函数的参数列表中推导出类型

    GCC遵循C++标准规定的规则。

    我是否应该每次都使用foo(arg,。。。)(提供类型),无论函数声明?

    那取决于你想要实现什么。 如果你想明确一点,那么就这么做吧。 这类似于调用C语言中的foo_t()函数,该函数没有模板也没有重载。 但是,如果您希望代码是泛型的(例如,因为它是在模板本身中调用的,或者因为您希望在将来的类型更改时更容易更改),那么您最好避免显式地编写类型。

    另一种选择是使用重载而不是模板。 您使用哪一个,再次,取决于您想要什么和您的用例。

    最后,您还可以使用auto:

    auto zero() { return 0; }
    

    话虽如此,但对于签名/接口,我认为最好的做法是处处使用显式类型,除非有理由不使用(例如它需要是模板):

    int zero() { return 0; }
    

    匿名用户

    定义语言规则来满足这种情况并不是不可能的,但这将是非同小可的,完全没有意义的。

    当决定其模板参数所需的所有信息都在该函数中时,该函数就不需要成为模板。 它应该只返回int,句号。 如果您出于某种原因不想拼出返回类型,这就是auto的用途:它将执行您所寻求的推演。

    另一方面,如果您希望根据模板参数将0转换为不同类型,那么这更有意义,并且您已经有了解决方案:提供模板参数(计算机如何猜到它?)。 在这个特定的示例中,您最好只是在调用站点进行转换,但您可能已经考虑了一些更复杂的逻辑。

    至于是否应该始终显式地给出模板参数,即使它们是可推导的,我认为这在某种程度上是一个风格问题。 另一方面,它看起来很无意义,也很嘈杂,但另一方面,它可以自我文档化,并确保您正在调用您认为正在调用的专门化。 所以我认为这要视情况而定。