3

I would like to do something like this:

#include <iostream>

class a {

public:
    a() : i(2) {}

    template <typename ...ts>
    void exec() {
        f<ts...>();
        std::cout << "a::()" << std::endl;
    }

    int i;
private:

    template <typename t>
    void f() {
        i += t::i;
    }

    template <typename t, typename ...ts>
    void f() {
        f<t>();
        f<t, ts...>();
    }
};

struct b {
    static const int i = -9;
};

struct c {
    static const int i = 4;
};


int main()
{
    a _a;

    _a.exec<b,c>();

    std::cout << _a.i << std::endl;
}

The idea is to get the same information from a group of classes, without the need of an object of each class.

Does anyone know if it is possible?

Thanks!

4
  • Are you looking for std::integral_constant? Or maybe make exec have template <int ...ts> template arguments? Commented May 29, 2018 at 20:08
  • 1
    f<t, ts...>(); would do infinite recursive call, you probably mean f<ts...>(); Commented May 29, 2018 at 20:09
  • Jarod42, you are right. I posted the code without this correction. But, even them, it does not compile, reporting ambiguous call from two calls to the same 'f'. Commented May 29, 2018 at 20:11
  • Variant of your code, using tag parameter to select correct overload Demo. Commented May 29, 2018 at 21:00

3 Answers 3

5

In case Your compiler does not support C++17:

template <typename ...ts>
void f() {
    for ( const auto &j : { ts::i... } )
        i += j;
}
Sign up to request clarification or add additional context in comments.

4 Comments

Which looks even better than folding expression IMO.
@Jarod42 It is shorter, not more readable. Can someone explain to me how this works, btw?
@NO_NAME Long story short - it creates an initializer list from is from all the classes and iterates over them. It works ONLY because the is are all the same type
I retract what I said. It only seem shorter because you didn't write code of the class. Although now, as I understand this, it strikes me that this loop is an exact equivalent to the @Jarod42 's code. C++17 just provides a shorter way (maybe also more flexible) to write such loops.
3

In C++17, your class would simply be

class a {

public:
    a() : i(2) {}

    template <typename ...ts>
    void exec() {
        ((i += ts::i), ...); // Folding expression // C++17
        std::cout << "a::()" << std::endl;
    }

    int i;
};

Possible in C++11 too, but more verbose.

Comments

1

Reasons why your code is not compiling:

  1. Syntax of specializing templates is a little different.
  2. You need to put the most general case first.
  3. You can't partially specialize functions, only classes.
  4. Partial specialization is not allowed within classes, only in namespaces.

Here is an example for C++11.

#include <iostream>

template<typename t, typename ...ts>
class a {
public:
    static constexpr int x = t::i + a<ts...>::x;
};

template<typename t>
class a<t> {
public:
    static constexpr int x = 2 + t::i;
};

struct b {
    static constexpr int i = -9;
};

struct c {
    static constexpr int i = 4;
};

int main()
{
    constexpr int result = a<b,c>::x;
    std::cout << result << std::endl;
}

Remember that templates are calculated during compilation so, for optimization sake, it is a good idea to write them in a way that allows them to be constexpr.

2 Comments

"Syntax of specializing templates is a little different": It is actually overloads and not specialization.
@Jarod42 I think that overloading applies only if functions have different parameters.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.