2

I have written a class template with the following signature:

template<typename ... Args> struct MyClass {};
template<typename ... A, B> struct MyClass< std::tuple<A ...>, B> {};

I have two closely related questions for this scenario, which both deal with the way partial specializations can be mapped onto each other. If, despite my more or less thorough search, these question have already been addressed here, I would also be glad with links to those threads.


Question 1: In the code, instead of writing

MyClass< std::tuple<>, B> myClass;

, I want to create the corresponding object as

MyClass<B> myClass;

My first approach to this was to use inheritance,

template<typename B>
struct Myclass<B> : public MyClass<std:tuple<>, B>
{
    typedef MyClass<std:tuple<>, B> Base;

    using Base::Function1;
    using Base::Function2;
    // ...
}

but, if I see it right, then I would have to bring the base-class functions to the derived-class namespace. Further, thinking more in principles, these classes shall be the "same" and not related via inheritance-like "is-an" relationship.

Is there any other way to do it, for example with using template aliasing (the using keyword)? E.g. as (but this does't work)

template<typename B> struct MyClass<B> = MyClass<std::tuple<>, B>;

Any other working alternatives are welcome, it shall set one partial specialization equal to the other without much overhead.


Question 2 is closely related at least as far I can see it. Generally, I would prefer to avoid writing "tuple" at all. So in the same non-working way as above, but more generally, I would want to write something like

template<typename ... A, typename B> struct MyClass<B, A ... > = MyClass<std::tuple<A ...>, B>;

(I interchanged the order of A ... and B in the specialization because at least Visual Studio wants to have the pack-expansion as the last parameter.)

Any help is appreciated, thanks in advance.


EDIT: It doesn't seem to work with template aliases, see here. Other alternatives are welcome.

Community
  • 1
  • 1
davidhigh
  • 14,652
  • 2
  • 44
  • 75

3 Answers3

4

You may use an extra level of indirection, something like:

template<typename ... Args> struct MyClass_impl {};
template<typename ... Ts, typename T> struct MyClass_impl<std::tuple<Ts ...>, T> {};

namespace detail
{
    template<typename T, typename ... Ts>
    struct Helper
    {
        using type = MyClass_impl<std::tuple<Ts...>, T>;
    };

    template<typename ... Args, typename ... Ts>
    struct Helper<std::tuple<Args...>, Ts...>
    {
        using type = MyClass_impl<std::tuple<Args...>, Ts...>;
    };

}

template <typename ... Ts>
using MyClass = typename detail::Helper<Ts...>::type;
Jarod42
  • 203,559
  • 14
  • 181
  • 302
1

but, if I see it right, then I would have to bring the base-class functions to the derived-class namespace.

I'm not sure what you mean here, but names from a public base class are already accessible in the derived class scope.

Is there any other way to do it, for example with using template aliasing (the using keyword)?

No. MyClass is a class template, it cannot also be an alias template.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • Thanks for the answer, so you suggest to use inheritance? With the first quote I meant [this](http://stackoverflow.com/questions/4643074/why-do-i-have-to-access-template-base-class-members-through-the-this-pointer). This prevents from taking an exact "copy" of the types via inheritance, as far as I can see. – davidhigh Aug 08 '14 at 13:36
  • That's only relevant inside the scope of the type, for users of the type they don't need the extra qualification. – Jonathan Wakely Aug 08 '14 at 13:39
  • Stated in other words: if I do it like this, it doesn't work, as the (non-virtual) function names are not known anymore. – davidhigh Aug 08 '14 at 13:42
  • More detailed: `MyClass, B> myClass; myClass.operator()(/* ...*/);` works, but `template struct MyClass : public MyClass, B> {};` and then `MyClass myClass; myClass.operator()(/* ...*/);` doesn't ... – davidhigh Aug 08 '14 at 13:50
  • No, that's not true. The second case should work fine. – Jonathan Wakely Aug 08 '14 at 14:00
  • Hmmm... there is your word against Visual Studio's error messages ... believe me, I'd like to believe you ... – davidhigh Aug 08 '14 at 14:17
  • I don't know what you're compiling but http://ideone.com/iEuZDF works fine. If your version fails it should not be to do with whatever is confusing you about name lookup. Names in a public base class are accessible in a derived class, that's just a fact. – Jonathan Wakely Aug 08 '14 at 14:26
  • my problem back then was some kind of function shadowing (--just came here almost a year later because of an upvote and thought I state this for clarity). – davidhigh May 17 '15 at 19:15
0

If I understand your question correctly, I think you may have answered it yourself.

typedef MyClass<std:tuple<>, B> Base;

Then you would just write

Base myClass;

The same should work for your other questions too.

Brad
  • 2,261
  • 3
  • 22
  • 32
  • Thanks, this would be a workaround for the first case, but not for the second. Also, for me personally, that seems a bit unsatisfying ... – davidhigh Aug 08 '14 at 19:37