使用模板化可变参数模板参数作为专用参数
Posted
技术标签:
【中文标题】使用模板化可变参数模板参数作为专用参数【英文标题】:Use a templated variadic template parameter as specialized parameter 【发布时间】:2014-04-16 20:15:13 【问题描述】:我的标题可能是错误的 - 如果是这样,请纠正我,但在某些时候我很难跟踪我实际想要实现的元目标;)
我有一个这样的类函数模板:
template<template<typename...> class MapType>
Expression Expression::substitute(MapType<std::string, Expression> const& identifierToExpressionMap) const
return SubstitutionVisitor<MapType>(identifierToExpressionMap).substitute(something);
重要的部分是 MapType。这个想法是允许随意插入std::map
或std::unordered_map
。使用 GCC 和 Clang,这是可行的,但 Visual Studio 2013 会引发编译错误:
error C2664: 'Expression Expression::substitute<:map>(const MapType &) const' : 无法将参数 1 从 'std::map<:string>,std::allocator<:pair _kty>>>' 转换为 'const std::地图 &' 1> 与 1> [ 1> MapType=std::map 1>] 1> 和 1> [ 1> _Kty=std::字符串 1> , _Ty=表达式 1>] 1> 原因:无法从 'std::map<:string>,std::allocator<:pair _kty>>>' 转换为 'const std ::地图' 1> 与 1> [ 1> _Kty=std::字符串 1> , _Ty=表达式 1>] 1> 没有可以执行此转换的用户定义转换运算符,或者无法调用该运算符
MSVC 好像没有把MapType
和<std::string, Expression>
作为一个类型放在一起,我是不是漏掉了什么?
所以我的问题是
-
这是否可能,只是 MSVC 中的一个错误,或者
有没有更简单的方法来做到这一点。请记住,还有许多其他类接收
MapType
参数并使用不同的键/值类型实例化它们自己的版本。
【问题讨论】:
当 MSVC 不同意 GCC 和 Clang 时,这是 MSVC 中的一个错误。 不幸的是,我现在没有 VS2013 可以测试,但由于回复不多,因此您可以测试以下内容:充实函数替代上的参数,使其具有 2 个默认参数地图的模板(std::less 和 std::allocator)。然后让substitute 的调用者尝试传入一个指定了所有模板参数的映射(即:它具有std::less 和std::allocator)。这里的测试是看如果所有模板参数在每一步都显式存在,VS是否处理得更好。 @qeadz 但是 unordered_map 的模板参数比 map 多 - 我可以 not 传递 std::map 并将所有参数指定为替换,因为它不再是模板并且我在类中需要不同的键/值类型 - 也许我不明白你的建议......? @qeadz 我想你提到了一个重要的问题:std::map
类模板实际上有四个模板参数,所以当用作模板时,它应该需要 template-argument 所有四个模板参数来实例化(因为默认参数没有传递给模板模板参数)。然而,一些例子用 clang++ 和 g++ 编译,不知道为什么。
哇...这似乎是一个悬而未决的问题:open-std.org/JTC1/SC22/WG21/docs/cwg_active.html#150
【参考方案1】:
大概是这样的:
template<class T, class U = int>
struct cat ;
template< template<class...> class Animal >
void foo()
Animal<int> x; (void)x; // (A)
int main()
foo<cat>();
这个看似无辜的小程序被clang++和g++接受,但不被MSVC2013 Update 1接受。
行 (A) 是有问题的:我认为在这个例子中,模板 template-parameter Animal
在传递类模板 cat
时应该有两个模板参数。
clang++ 和 g++ 似乎支持在 (A) 行中为此模板 template-parameter 使用默认模板参数,而 MSVC 不支持。
我不知道标准是否需要其中任何一个;见例子
this answer by Richard Smith CWG active issue #150在我看来,支持默认模板参数当然很有用,因为(正如在活动问题中所说)标准库的类模板可能有额外的模板参数(带有默认参数);如果您想(直接)将它们用作模板template-arguments,则需要了解这些实现细节。
【讨论】:
【参考方案2】:鉴于已经发生的讨论,我认为也许是时候考虑解决方法了。由于推断模板模板参数似乎是手头的问题,也许放宽对 MapType 的要求可能会有所帮助。
template< typename MapType>
Expression Expression::substitute( MapType const& identifierToExpressionMap) const
return SubstitutionVisitor<MapType>(identifierToExpressionMap).substitute(something);
调用者将被编译为调用函数的代码,因此编译器将推导出模板参数,因此基本上您将使用正确的 std::map 或 std::unordered_map 的责任推给调用者。
现在至少在大多数情况下这可能有效。但是,可以传入某种可以编译但实际上没有正确类型的容器。所以理想情况下,您仍然需要某种编译时检查以确保支持 MapType(即:std::map 或 std::unordered_map)。
这可以通过 Boost 概念,或者甚至只有两个模板化别名声明 - 使用 enable_if 可以确保别名声明仅在两种风格中可用:map 或 unordered_map。
【讨论】:
我接受了另一个答案,因为那里描述了实际的原因和问题,所以对于任何有类似问题的人来说,我可能会更有用。很抱歉,你们都给出了很好的见解。以上是关于使用模板化可变参数模板参数作为专用参数的主要内容,如果未能解决你的问题,请参考以下文章