Cascades
Cascades

Reputation: 644

Reducing duplication of template parameters in C++

This is not a major code breaking issue, I'm just wondering if I'm missing some neat trick.

If I am writing a templated class, I may start like this:

// some_header.h
template <typename TypeParameter, size_t max_array_size>
class TemplatedClass
{
    std::array<TypeParameter, max_array_size> MyTemplatedArray;

public:
    TypeParameter do_something()
    {
        /* do something with TypeParameter and max_array_sizein here */
    }
}

This is fine, but when I have less trivial templated examples, I tend to separate out the function definitions from the declarations, like so:

// some_header.h
template <typename TypeParameter, size_t max_array_size>
class TemplatedClass
{
    std::array<TypeParameter, max_array_size> MyTemplatedArray;

public:
    TypeParameter do_something();

    /*

    Many more function declarations

    */
}

template <typename TypeParameter, size_t max_array_size>
TemplatedClass<TypeParameter, max_array_size>::do_something()
{
    /* do something with TypeParameter and max_array_sizein here */
}

/*

Many more function definitions, all with:

template <typename TypeParameter, size_t max_array_size>
TemplatedClass<TypeParameter, max_array_size>

at the start

*/

The aim of this would be to have a classic skeleton class definition that can easily be read by others at a glance. I don't mind doing this, but the annoying thing is when I want to modify the template parameters. What is one change in the first example, ends up being 1 + 2 * n changes in the second example!

So what I am wanting to know is: Is there a way to make the second example's template parameters more maintainable? Maybe something similar to a typedef/using or maybe some keyword I haven't heard of?

Upvotes: 3

Views: 169

Answers (1)

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122450

First a non-answer:

Suppose, /*do something*/ depends on the template parameters. In that case, having to fix the signature is the smaller issue. You need to fix the implementation.

The other case is that /*do something*/ does not depend on the template parameters. Then you can move the methods to a non template base class.


A more serious attempt to answer the question:

What if TemplatedClass would have only a single template parameter instead of many? Instead of using a bunch of template parameters for TemplatedClass you can use a single tag and definition of the actual parameters can be defered to traits:

#include <array>

template <typename Tag> struct value_type_impl;
template <typename Tag> using value_type = typename value_type_impl<Tag>::type;
template <typename Tag> constexpr int array_size = 123;

template <typename Tag>
class TemplatedClass {
    std::array<value_type<Tag>, array_size<Tag> > MyTemplatedArray;    
public:
    value_type<Tag> do_something();
};

template <typename Tag>
value_type<Tag> TemplatedClass<Tag>::do_something() {
    return {};
}

// the tag
struct foo_tag{};

// specializations for foo_tag:
template <> struct value_type_impl<foo_tag> { using type = int; };
template <> constexpr int array_size<foo_tag> = 123;


int main() {
    TemplatedClass<foo_tag> tc;
}

Now the burdon is on the user of the template to define one tag and then specialize the required traits for that tag. Though, the method definition has only a single template parameter that does not need to change when more "parameters" (traits) are added or removed. Of course you still need to fix the implementation.

If you were looking merely for some syntactic sugar, I am not aware of something that would help without changing the template itself.

Upvotes: 1

Related Questions