c++c++-templates

How can I alias "away" a template parameter that is not used for a template specialization?


The issue I am having is that for the nested specialization template <foo_t T, int I, typename S> struct foo<T, I, S> I am not using the template parameter int I at all.

I would like to have a way to alias "away" that parameter so that I don't have to write that useless parameter for nested foo variables. I tried two ways but none of them work. I am curious to see if there even is a way to do that cleanly. Can you help me out?

Code example

#include <iostream>

template <typename T> concept foo_base_t = requires { typename T::base_tag; }; 
template <typename T> concept foo_nested_t = requires { typename T::nested_tag; }; 
template <typename T> concept foo_t = foo_base_t<T> or foo_nested_t<T>; 

template <typename T> concept bar_base_t = requires { typename T::base_tag; }; 
template <typename T> concept bar_nested_t = requires { typename T::nested_tag; }; 
template <typename T> concept bar_t = bar_base_t<T> or bar_nested_t<T>; 

// Version 1 doesn't work
//=============================
template <typename T, int I, typename S> 
struct foo
{ 
    using base_tag = void; 
};

template <foo_t T, typename S> 
struct foo<T, 1, S>
{ 
    using nested_tag = void; 
};
//=============================

// Version 2 doesn't work
//=============================
template <typename T, int I, typename S> 
struct bar_impl
{ 
    using base_tag = void; 
};

template <bar_t T, int I, typename S> 
struct bar_impl<T, I, S>
{ 
    using nested_tag = void; 
};

template <typename T, int I, typename S> 
using bar = bar_impl<T, I, S>;

template <bar_t T, typename S> 
using bar<T, S> = bar_impl<T, 1, S>;
//=============================

int main()
{
    using T = foo<int, 1, int>;
    foo<T, int> o;

    using U = bar<int, 1, int>;
    bar<U, int> o;
}

Solution

  • I'm a bit unclear about your precise requirements TBH, but is this closer to what you're really trying to do (similar to Jarod42's comment - he beat me to it - but "foo_t" below or similar may be closer to what you're after) ...

    Click here to run

    #include <type_traits>
    #include <iostream>
    
    template <typename T, int I, typename S> 
    struct foo
    { 
        using base_tag = void; 
    };
    
    namespace details
    {
        template <typename T>
        struct is_foo_impl : public std::false_type
        {
        };
    
        template <typename T,
                  int I,
                  typename S>
        struct is_foo_impl<foo<T, I, S>> : public std::true_type
        {
        };
    }
    
    template <typename T>
    concept foo_t = details::is_foo_impl<std::remove_cv_t<T>>::value;
    
    template <foo_t T,
              typename S>
    using nested_foo = foo<T, 1, S>;
    
    int main()
    {
        using T = foo<int, 1, int>;
        nested_foo<T, int> o;
    }