Tobias Langner
Tobias Langner

Reputation: 10828

How can I create a template version of this method that is used when template parameter is std::vector

I currently have the following problem. I have the following class:

class Container
{
public:
    explicit Container(Resolver& r);
    ~Container();

    template <typename Interface>
    Interface& Create();

    size_t GetNumberOfManagedObjects();
private:

    template <typename Interface>
    Interface& InternalCreate();

    Resolver& m_resolver;
    std::vector<std::pair<std::function<void(void*)>,intptr_t>> m_deleter;
    std::unordered_map<std::string,intptr_t> m_singletons;
};

now I need a version of InternalCreate that is used when the template parameter 'Interface' is of type std::vector, and I need a version that is used otherwise. Is that possible (e.g. using std::enable_if)? From what I've read, partial specialization is not possible in this case but I can't fully specify the types inside the vector. Can someone help?

Regards Tobias

Upvotes: 1

Views: 73

Answers (2)

Brian Bi
Brian Bi

Reputation: 119457

Using a helper function, you can take advantage of template parameter deduction. Here's an example which you can adapt to your program:

#include <iostream>
#include <vector>
class Foo {
  public:
    template <typename T>
    T Create() {
        return helper(static_cast<T*>(nullptr));
    }
  private:
    template <typename T>
    static T helper(T*) {
        std::cout << "Using generic helper\n";
        return {};
    }
    template <typename T>
    static std::vector<T> helper(std::vector<T>*) {
        std::cout << "Using specialized helper\n";
        return {};
    }
};
int main() {
    Foo f;
    f.Create<int>();
    f.Create<int*>();
    f.Create<std::vector<int>>();
    f.Create<std::vector<int>*>();
    f.Create<std::vector<std::vector<int>>>();
    return 0;
}

Output:

Using generic helper
Using generic helper
Using specialized helper
Using generic helper
Using specialized helper

Upvotes: 0

David G
David G

Reputation: 96845

SFINAE seems to be the correct solution here. You can create a trait which returns std::true_type when the type it receives is a vector:

template<typename Container>
struct is_vector : std::false_type { };

template<typename T>
struct is_vector<std::vector<T>> : std::true_type { };

Now you can enable an overload for a vector like this:

template <typename Interface>
    Interface& InternalCreate(
           typename std::enable_if<is_vector<Interface>{}>::type* ptr = nullptr);

template <typename Interface>
    Interface& InternalCreate(
          typename std::enable_if<!is_vector<Interface>{}>::type* ptr = nullptr);

Upvotes: 1

Related Questions