带有模板模板参数的 C++ 函数失败模板参数 deduction/substitution

C++ function with template template argument fail template argument deduction/substitution

我正在尝试使用模板参数为 C++ STL 容器编写通用幂集函数。问题归结为以下模板参数 deduction/substitution 失败:

template <typename T, template<typename> class C>
C<C<T>> getPowerSet(typename C<T>::iterator begin, typename C<T>::iterator end)
...
vector<vector<int>> powerSet = getPowerSet<int, vector>(set.begin(), set.end());

代码和编译器错误(使用 g++ (GCC) 4.8.1 20130531 (Red Hat 4.8.1-1))如下。我注释掉了与编译器错误无关的部分。

#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>
using namespace std;

template <typename T, template<typename> class C>
C<C<T>> getPowerSet(typename C<T>::iterator begin, typename C<T>::iterator end)
{
    C<C<T>> powerSet;
    /*
    if (begin == end)
        return powerSet;

    C<C<T>> subproblem = getPowerSet(begin + 1, end);
    copy(subproblem.begin(), subproblem.end(), inserter(powerSet, powerSet.end()));
    for (C<T> set : subproblem)
    {
        *inserter(set, set.begin()) = *begin;
    }
    copy(subproblem.begin(), subproblem.end(), inserter(powerSet, powerSet.end()));
    */
    return powerSet;
}

int main()
{
    vector<int> set;
    for(int i = 0; i < 5; ++i)
        set.push_back(i);
    vector<vector<int>> powerSet = getPowerSet<int, vector>(set.begin(), set.end());
    /*
    for (auto set : powerSet)
    {
        for (int elem : set)
        {
            cout << elem << " ";
        }
        cout << endl;
    }
    */
}

编译错误如下:

[thomas.bao@cwdev01 recursion]$ g++ 3.cpp
3.cpp:8:15: error: template argument 1 is invalid
 C<typename C<T>> getPowerSet(typename C<T>::iterator begin, typename C<T>::iterator end)
               ^
3.cpp: In function ‘int main()’:
3.cpp:31:83: error: no matching function for call to ‘getPowerSet(std::vector<int>::iterator, std::vector<int>::iterator)’
     vector<vector<int>> powerSet = getPowerSet<int, vector>(set.begin(), set.end());
                                                                                   ^
3.cpp:31:83: note: candidate is:
3.cpp:8:18: note: template<class T, template<class> class C> int getPowerSet(typename C<T>::iterator, typename C<T>::iterator)
 C<typename C<T>> getPowerSet(typename C<T>::iterator begin, typename C<T>::iterator end)
                  ^
3.cpp:8:18: note:   template argument deduction/substitution failed:

朋友通过电子邮件向我发送了以下内容 gem(该死的默认模板参数):

#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>
using namespace std;

template <typename T, typename S, template<typename, typename> class C>
C<C<T, S>, std::allocator<C<T, S> > > getPowerSet(typename C<T, S>::iterator begin, typename C<T, S>::iterator end)
{
  C<C<T, S>, std::allocator<C<T, S> > > powerSet;
    /*
    if (begin == end)
        return powerSet;

    C<C<T>> subproblem = getPowerSet(begin + 1, end);
    copy(subproblem.begin(), subproblem.end(), inserter(powerSet, powerSet.end()));
    for (C<T> set : subproblem)
    {
        *inserter(set, set.begin()) = *begin;
    }
    copy(subproblem.begin(), subproblem.end(), inserter(powerSet, powerSet.end()));
    */
    return powerSet;
}

int main()
{
    vector<int> set;
    for(int i = 0; i < 5; ++i)
        set.push_back(i);
    auto powerSet = getPowerSet<int, std::allocator<int>, vector>(set.begin(), set.end());
    /*
    for (auto set : powerSet)
    {
        for (int elem : set)
        {
            cout << elem << " ";
        }
        cout << endl;
    }
    */
}

如果您更改签名以采用带有可变参数列表的模板参数

template <typename T, template<typename...> class C>
//                             ^^^^^^^^^^^
C<C<T>> getPowerSet(typename C<T>::iterator begin, typename C<T>::iterator end)

您不再需要将分配器类型添加到调用中。