【问题标题】:C++ template parameter with default parameters具有默认参数的 C++ 模板参数
【发布时间】:2015-02-04 15:25:09
【问题描述】:

我有一个类需要使用某种地图。默认情况下,我想使用std::map,但我也想让用户能够根据需要使用不同的东西(例如std::unordered_map,甚至可能是用户创建的)。

所以我的代码看起来像

#include <map>

template<class Key, template<class, class> class Map = std::map>
class MyClass {
};

int main() {
  MyClass<int> mc;
}

但是,g++ 抱怨

test.cpp:3:61: error: template template argument has different template parameters than its corresponding template template parameter
template<class Key, template<class, class> class Map = std::map>
                                                            ^
test.cpp:8:14: note: while checking a default template argument used here
  MyClass<int> mc;
  ~~~~~~~~~~~^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/map:781:1: note: too many template parameters in template template argument
template <class _Key, class _Tp, class _Compare = less<_Key>,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:3:21: note: previous template template parameter is here
template<class Key, template<class, class> class Map = std::map>
                    ^~~~~~~~~~~~~~~~~~~~~~
1 error generated.

所以看起来g++ 不高兴std::map 有默认参数。

有没有办法让Map 成为任何可以接受至少两个模板参数的模板?

如果可以的话,我更愿意坚持使用 C++98,但我对 C++11 持开放态度。

【问题讨论】:

  • 如果你对 C++11 持开放态度,你可以说template &lt;typename...&gt; class Map = std::map,但真正的解决方案是在类型上参数化,而不是在模板上。
  • @KerrekSB 我最初是这样做的,但我需要 Map 和 Map。我也有这些的默认模板参数,但我认为如果用户可以只指定 Map 并且如果他们没有指定 Map 或 Map 会很方便,这些将自动确定.有没有更好的方法来避免模板模板参数?

标签: c++ templates


【解决方案1】:

您的代码将在 C++17 中编译。 C++ 核心工作组 (CWG 150) 的长期缺陷报告已及时解决(P0522R0)在 C++17 之前。

cppreference.com 也讨论此here,并提供一个有用的示例:

template<class T> class A { /* ... */ };
template<class T, class U = T> class B { /* ... */ };
template <class ...Types> class C { /* ... */ };

template<template<class> class P> class X { /* ... */ };
X<A> xa; // OK
X<B> xb; // OK in C++17 after CWG 150
         // Error earlier: not an exact match
X<C> xc; // OK in C++17 after CWG 150
         // Error earlier: not an exact match

使用我的 GCC (8.3.0) 版本进行测试,我发现使用 -std=c++17 标志将成功编译您的程序;而使用早期版本的 C++(例如 -std=c++14-std=c++11)会失败。

【讨论】:

    【解决方案2】:

    问题是您的模板模板参数只有两个模板参数,而map 有四个。

    template<class Key, template<class, class, class, class> class Map = std::map>
    class MyClass {
    };
    

    或者

    template<class Key, template<class...> class Map = std::map>
    class MyClass {
    };
    

    Should compile.
    但是,为避免此类问题,请尝试使用 map 类型,并通过相应的成员 typedef 提取键类型。例如

    template <class Map>
    class MyClass {
        using key_type = typename Map::key_type;
    };
    

    【讨论】:

    • 谢谢! g++ 很高兴。但是,这禁止 Map 类型选择接受模板模板参数或类型以外的任何参数,对吗?出于好奇,有没有办法让Map 的可选参数成为任何东西?
    • @0x499602D2 这正是我在帖子最后一句中提出的建议。
    • @math4tots 不,那是不可能的。 (还有一个流行的未回答的 SO 帖子关于这个问题的某个地方......)这就是为什么你应该使用地图类型而不是模板的原因。它更加灵活。
    • @0x499602D2 来源?在后厄巴纳邮件中看不到任何内容。
    • @0x499602D2 这些都与采用任意种类的模板参数无关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-09
    • 2019-09-12
    • 2011-08-27
    • 2018-10-12
    • 1970-01-01
    相关资源
    最近更新 更多