简体   繁体   English

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

[英]Use a templated variadic template parameter as specialized parameter

My title might be wrong - if so, please do correct me, but at some point its hard for me to keep track of what meta thingy I'm actually trying to achieve ;) 我的头衔可能是错的 - 如果是这样,请纠正我,但在某些时候我很难跟踪我实际上想要实现的东西;)

I have a class function template like this: 我有一个类函数模板,如下所示:

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

The important part is the MapType. 重要的部分是MapType。 The idea is to allow either std::map or std::unordered_map to be plugged in at will. 这个想法是允许std::mapstd::unordered_map随意插入。 With GCC and Clang, this works, but Visual Studio 2013 throws a compilation error: 使用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

It seems that MSVC does not put MapType and <std::string, Expression> together as a type, am I missing something here? 似乎MSVC没有把MapType<std::string, Expression>放在一起作为一个类型,我在这里遗漏了什么?

So my question is 所以我的问题是

  1. is this possible and just a bug in MSVC, or 这是可能的,只是MSVC中的一个错误,或者
  2. is there an easier way to do this. 是否有更简单的方法来做到这一点。 Please keep in mind that there are many other classes which receive the MapType parameter and instantiate their own version with different key/value Types. 请记住,还有许多其他类接收MapType参数,并使用不同的键/值类型实例化自己的版本。

It probably boils down to this: 它可能归结为:

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>();
}

This little innocent-looking program is accepted by clang++ and g++, but not by MSVC2013 Update 1. 这个看似无辜的小程序被clang ++和g ++接受,但不是MSVC2013 Update 1。


Line (A) is the problematic one: I think in this example it's clear that the template template-parameter Animal should have two template parameters, when passing the class template cat . 线(A)是有问题的:我认为在这个例子中很明显模板模板参数 Animal在传递类模板cat时应该有两个模板参数。

It seems that clang++ and g++ support the use of default template arguments for this template template-parameter in line (A), while MSVC does not. 似乎clang ++和g ++支持在行(A)中使用此模板模板参数的默认模板参数,而MSVC则不支持。

I do not know if the Standard requires either of them; 我不知道标准是否要求其中任何一个; see for example 例如,看看

It certainly appears to me that supporting the default template arguments is useful, since (as said in the active issue) the class templates of the Standard Library may have additional template parameters (with default arguments); 在我看来,支持默认模板参数很有用,因为(如活动问题中所述)标准库的类模板可能有其他模板参数(使用默认参数); and you'd need to know those implementation-details if you wanted to use them (directly) as template template-arguments . 如果你想(直接)使用它们作为模板模板参数 ,你需要知道那些实现细节。

Given the discussion which has happened I think maybe it would be time to consider a work-around. 鉴于已经发生的讨论,我想也许是时候考虑解决方案了。 Since deducing the template template arguments seems to be the issue at hand, perhaps relaxing the requirements for MapType might be helpful. 由于推断模板模板参数似乎是手头的问题,因此放宽MapType的要求可能会有所帮助。

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

The caller is going to be compiled code calling a function and so the compiler will deduce the template arguments so basically you're pushing the responsibility of using the proper std::map or std::unordered_map onto the caller. 调用者将被编译为调用函数的编译代码,因此编译器将推导出模板参数,因此基本上你要将使用正确的std :: map或std :: unordered_map的责任推到调用者身上。

Now at least for most cases this may work. 现在,至少在大多数情况下,这可能有效。 However it is possible to pass in some kind of container which compiles but doesn't actually have the right types. 但是,可以传入某种编译但实际上没有正确类型的容器。 So ideally you'd still be wanting some kind of compile-time check to ensure MapType is supported (ie: either a std::map or std::unordered_map). 理想情况下,您仍然需要进行某种编译时检查以确保支持MapType(即:std :: map或std :: unordered_map)。

This could be via Boost concepts, or even just having two templated alias declarations - using enable_if you can ensure that the alias declaration is only available in two flavors: map or unordered_map. 这可以通过Boost概念,或者甚至只有两个模板化的别名声明 - 使用enable_if可以确保别名声明只有两种版本:map或unordered_map。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM