c++templates

Using a class template in the template parameter of a function template


I have a Foo class template with two template parameters, and a constructor using a vector. I also define some aliases for (partial) specializations (FooOne, FooTwo, FooThree). I want the user to not have to worry about the types of these (and size of FooThree). I also want the user to be able to make Foo from bytes; however, since I already have a constructor with the same prototype and it's not an intuitive way to build Foo, I want it as a separate function makeFromBytes.

#include <array>
#include <vector>



template <typename T, size_t S>
class Foo
{
public:
    Foo() { }
    Foo(const std::vector<T>& data) { /* ... */ }

    template <typename T, size_t S>
    friend Foo<T, S> makeFromBytes(const std::vector<char>& bytes);

private:
    std::array<T, S> m_data{ };
};

template <typename T, size_t S>
Foo<T, S> makeFromBytes(const std::vector<char>& bytes)
{
    Foo<T, S> result{ };
    /* ... */
    return result;
}



template <size_t S>
using FooOne = Foo<char, S>;
template <size_t S>
using FooTwo = Foo<int, S>;
using FooThree = Foo<int, 4>;

The syntax I want the user to use would look like this: makeFromBytes<FooOne<2>> and makeFromBytes<FooThree> that translate into makeFromBytes<char, 2> and makeFromBytes<int, 4> respectively.

I have tried many syntaxes (and googling) but it seems like C++ doesn't allow it.

Is there any way to get this clean syntax ? Other solutions are :

Am I missing something with the syntax ? Is there any trick or better solution ? Thanks for your help.


Solution

  • You were really close to the solution. To get the syntax you desire, you only need to implement the function you declared:

    template <class C>
    C makeFromBytes(const std::vector<char>& bytes) {
        C result{ }; // C is Foo<T, S>
        /* ... */
        return result;
    }
    

    If from within foo you need T or S, you can declare them in your class:

    template <typename T, size_t S>
    class Foo
    {
    public:
        using value_type = T;
        static constexpr size_t size = S;
    
       // ...
    };
    

    Then use it inside the function:

    template <class C>
    C makeFromBytes(const std::vector<char>& bytes) {
        C result{ }; // C is Foo<T, S>
        using T = typename C::value_type;
        static constexpr size_t S = C::size;
        /* ... */
        return result;
    }