模板化的模板参数名称在方法头上无效

Templated template argument name is invalid on the head of the method

本文关键字:方法 无效 参数      更新时间:2023-10-16

我有以下示例代码:

template<int Size, template<typename Tin, int S> typename Cin, template<typename Tout, int S> typename Cout>
Cout<Tout, Size> SomeTemplatedMethod(const Cin<Tin, Size> &inputData) /* Here the definition fails on Tout and Tin as unknown. */
{
Cout<Tout, Size> result; // Here Tout doesnt fail!
//Whichever we do with inputData and result
return result;
}

代码在方法的标头中失败,但在正文中没有!我发现解决这个问题的一种方法是这样做:

template<int Size, template<typename, int> typename Cin, template<typename, int> typename Cout, typename Tin, typename Tout>
Cout<Tout, Size> SomeTemplatedMethod(const Cin<Tin, Size> &inputData) /* Here the definition doesn't fail. */
{
Cout<Tout, Size> result; // Here Tout doesnt fail!
//Whichever we do with inputData and result
return result;
}

但我肯定想用第一种方式,因为它感觉更干净。。。

我正在使用vc++14。我做错了什么?,这是一个bug还是一种预期行为?

谢谢!

这是预期行为。

来自【basic.scope.el】/1:

template-template-parameter是引入名称的最小的模板参数列表

并且,来自[basic.scope.el]/3:

模板参数名称的潜在作用域从其点开始的声明,并在其声明性区域的末尾结束。

因此,在上面的第一个示例中,例如Tin的声明性区域是引入它的模板参数列表,其作用域的末尾是该模板参数列表的末尾。例如,您可以使用Tin作为template< template< typename Tin, Tin arg> class Cin, ...,但不能使用Tin声明超出其范围的名称。

最后,请注意,对于C++14及更早版本,template<...> typename TT>是不合法的,因为模板模板参数声明可能只使用class关键字,而不使用typename(您的示例在C++14中也应该失败(。除非有编译器扩展,否则在C++14中,您需要使用template<...> class TT>。引用cppreference/template_parameters:

与类型模板参数声明不同,模板模板参数声明只能使用关键字class而不能使用typename(直到C++17(

但我肯定想使用第一种方式,因为它感觉更干净。。。

我知道这更干净,但肯定不起作用,因为TinToutS的声明范围仅限于CinCout的声明。(有关更好的解释,请参阅dfri的回答(。

因此,您必须在SomeTemplateMethod()的模板参数列表中声明TinTout(作为Size(。

您的第二个版本有效,但不是最佳版本。

注意,您有五个模板参数(TinToutCinCoutSize(,并且其中只有三个(CinTinSize(是可推导的(根据参数inputData的类型(。

所以您必须至少显式其中两个ToutCout

如果你把ToutCout放在模板参数列表的第三和第五位,就像在你的工作代码中一样,你必须显式显示所有五个模板参数,所以你必须调用下面的函数

MyCin<int, 42> mcin;
auto mcout = SomeTemplatedMethod<42, MyCin, MyCout, int, float>(mcin);

我建议在之前放置不可推导的模板参数,在之后放置可推导的参数,例如(也使用class而不是typename声明模板模板参数;C++17之前需要(

template <typename Tout, template <typename, int> class Cout,
typename Tin, template <typename, int> class Cin,
int Size>
Cout<Tout, Size> SomeTemplatedMethod (Cin<Tin, Size> const & inputData) 

这样你只需要显式的两个不可推导的参数

MyCin<int, 42> mcin;
auto mcout = SomeTemplatedMethod<float, MyCout>(mcin);

以下是一个完整的编译示例(但我已将int更改为std::size_t以获得大小(

#include <array>
template <typename Tout, template <typename, std::size_t> class Cout,
typename Tin, template <typename, std::size_t> class Cin,
std::size_t Size>
Cout<Tout, Size> SomeTemplatedMethod (Cin<Tin, Size> const &)
{
Cout<Tout, Size> result;
return result;
}
int main ()
{
std::array<int, 42u> x;
auto y = SomeTemplatedMethod<float, std::array>(x);
static_assert( std::is_same<decltype(y), std::array<float, 42u>>::value,
"!" );
}