使用模板化可变参数模板参数作为专用参数

时间:2014-04-16 20:15:14

标签: c++ templates c++11 variadic-templates

我的头衔可能是错的 - 如果是的话,请纠正我,但在某些时候我很难跟踪我实际上想要实现的东西;)

我有一个像这样的类函数模板:

template<template<typename...> class MapType>
    Expression Expression::substitute(MapType<std::string, Expression> const& identifierToExpressionMap) const {
        return SubstitutionVisitor<MapType>(identifierToExpressionMap).substitute(something);
    }

重要的部分是MapType。我们的想法是允许std::mapstd::unordered_map随意插入。使用GCC和Clang,这可行,但Visual Studio 2013会抛出编译错误:

error C2664: 'Expression Expression::substitute<std::map>(const MapType &) const' :

cannot convert argument 1 from 'std::map<std::string,Expression,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>' to 'const std::map &'

1>          with
1>          [
1>              MapType=std::map
1>          ]
1>          and
1>          [
1>              _Kty=std::string
1>  ,            _Ty=Expression
1>          ]

1>          Reason: cannot convert from 'std::map<std::string,Expression,std::less<_Kty>,std::allocator<std::pair<const _Kty,_Ty>>>' to 'const std::map'

1>          with
1>          [
1>              _Kty=std::string
1>  ,            _Ty=Expression
1>          ]

1>          No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

似乎MSVC没有将MapType<std::string, Expression>放在一起作为一种类型,我在这里遗漏了什么?

所以我的问题是

  1. 这是可能的,只是MSVC中的一个错误,或
  2. 有更简单的方法可以做到这一点。请记住,还有许多其他类接收MapType参数,并使用不同的键/值类型实例化自己的版本。

2 个答案:

答案 0 :(得分:4)

这可能归结为:

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则不支持。

我不知道标准是否要求其中任何一个;例如,参见

在我看来,支持默认模板参数很有用,因为(如活动问题中所述)标准库的类模板可能有其他模板参数(使用默认参数);并且如果您想(直接)将它们用作模板模板参数,您需要了解这些实现细节。

答案 1 :(得分:1)

鉴于已经发生的讨论,我想也许是时候考虑解决方案了。由于推断模板模板参数似乎是手头的问题,因此放宽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。