alto
alto

Reputation: 241

Syntax to refer to a template (alias?)

I'm working on porting some Julia code to C++ and have run into a problem. To make matters worse I'm not very familiar with the C++ nomenclature, so haven't been able to google my way out.

Basically, I'm trying to figure out how to refer to a template (is this a template alias?) so I can use it later, i.e., to refer to a type. I've tried various incantations involving using, typename, and template, but nothing seems to make my compiler happy. I have managed to produce something which does what I want (see below), but it is pretty nasty. Is there a better way? Any reasonable C++ is fine.

The following code is a minimal example of what I'm trying to achieve

#include <iostream>
#include <type_traits>

template<int n, template<int> class T>
int unwrap(T<n>& x) { return n; }

template<int n>
struct A { static const char name = 'A'; };

template<int n>
struct B { static const char name = 'B'; };

template<bool flag>
struct promote_if {
    template<int n> using type = A<n>;
};

template<> 
struct promote_if<true> {
    template<int n> using type = B<n>;
};

template<int m, int n, 
template<int> class X, 
template<int> class Y, 
template<int> class Z>
struct Stuff { static const int seven = 7; };

// Add type parameters and return 
// B<m + n> if X or Y is a B,
// otherwise return A<m + n>
template<int m, int n, template<int> class X, template<int> class Y> 
auto add(X<m>& x, Y<n>& y) {
    static const bool any = std::is_base_of<B<m>, X<m>>::value || std::is_base_of<B<n>, Y<n>>::value;
    // This works, but is gross
    std::cout << Stuff<m,n,promote_if<any>::template type,X,Y>::seven << "\n";
    typename promote_if<any>::template type<m + n> z;

    // Something like this is what I'm trying to achieve
    // using T = typename promote_if<any>::template type;
    // T<m + n> z;
    // std::cout << Stuff<m,n,T,X,Y>::seven << "\n";
    return z;
}

int main(int argc, char const *argv[]) {
    A<1> a;
    B<2> b;
    auto c = add(a, a);
    std::cout << "c = add(a, a) = " << c.name << "<" << unwrap(c) << ">\n";

    auto d = add(a, b);
    std::cout << "d = add(a, b) = " << d.name << "<" << unwrap(d) << ">\n";
    return 0;
}
// Output
// Stuff is 7
// c = add(a, a) = A<2>
// Stuff is 7
// d = add(a, b) = B<3>

Upvotes: 0

Views: 71

Answers (1)

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145359

Instead of

template<int m, int n, template<int> class X, template<int> class Y> 
auto add(X<m>& x, Y<n>& y) {
    static const bool any = std::is_base_of<B<m>, X<m>>::value || std::is_base_of<B<n>, Y<n>>::value;
    // This works, but is gross
    std::cout << Stuff<m,n,promote_if<any>::template type,X,Y>::seven << "\n";
    typename promote_if<any>::template type<m + n> z;

    // Something like this is what I'm trying to achieve
    // using T = typename promote_if<any>::template type;
    // T<m + n> z;
    // std::cout << Stuff<m,n,T,X,Y>::seven << "\n";
    return z;
}

try

// Add type parameters and return 
// B<m + n> if X or Y is a B,
// otherwise return A<m + n>
template<int m, int n, template<int> class X, template<int> class Y> 
auto add(X<m>& x, Y<n>& y) {
    static const bool any = std::is_base_of<B<m>, X<m>>::value || std::is_base_of<B<n>, Y<n>>::value;

    using T = promote_if<any>;
    typename T::template type<m + n> z;
    std::cout << Stuff<m,n,T::template type,X,Y>::seven << "\n";
    return z;
}

I just tried some combinations of typename and template and so on and let the g++ compiler's diagnostics steer me towards working code.

I think this is still ugly, though.

A probably better solution would be to rethink the whole thing and change the design.

Upvotes: 1

Related Questions