Search code examples
c++templatesc++11vectorgeneric-programming

function of generic container of specific specialization


I'm trying to write an algorithm that should work with different containers (std::vector, QVector) containing the same type:

template<class Container>
boolean findpeaks(cv::Mat &m, Container<std::pair<int, double>> &peaks) {
    // do stuff
    peaks.push_back(std::make_pair(1, 1.0));

    return true;
}

This one gives me

'Container' is not a template

template<template<typename> class Container>

I get:

error: no matching function for call to 'findpeaks(cv::MatExpr, std::vector >&)'

...

note: template argument deduction/substitution failed:

error: wrong number of template arguments (2, should be 1)

Calling code:

cv::Mat m(data, true);
std::vector<std::pair<int, double>> peaks;

QVERIFY(daf::findpeaks(m.t(), peaks));

I've also tried something like this:

template<template< template<typename, typename> typename > class Container>

warning: ISO C++ forbids typename key in template template parameter; use -std=c++1z or -std=gnu++1z [-Wpedantic]

And some more errors...


Solution

  • Just as expressed with @Barry's answer, I don't think you need a template template parameter here.

    However, you seem to have concern about expressing "a container that supports push_back with a pair of..."

    I suggest you to express this constraint in a sfinae constraint expression instead. Even if your parameter is explicitly requiring std::pair to be in the first template parameter of a class, it doesn't mean it has a push_back function, and doesn't mean the supposedly existing push_back is taking a std::pair as parameter.

    Arguments of a function is currently a bad way of expressing what a template type should be able to do, or should be. You'll have to wait for concepts for that.

    In the meantime, you can use a sfinae constraint in your function signature that explicitly express that you need a type that has a member push_back function that accept a std::pair:

    template<class Container>
    auto findpeaks(cv::Mat &m, Container& peaks)
            // Using trailing return type
            -> first_t<bool, decltype(peaks.push_back(std::make_pair(1, 1.0)))>
            // Here's the constraint -^    that expression need to be valid
        {
    
        // do stuff
        peaks.push_back(std::make_pair(1, 1.0));
    
        return true;
    }
    

    first_t can be implemented that way:

    template<typename T, typename...>
    using first_t = T;
    

    For the function to exist, the expression inside the decltype must be valid. If the contraint is not satified, the compiler will try other overloads of the function findpeaks.