2

I am having trouble declaring the following:

// c++17
template<typename T, typename ...Before, T v, typename ...After, template<typename ..., T, typename ...> U>
auto enum_to_type() {
    // do things with
    // U<Before..., v, After...> obj;
    // as an example:
    return U<Before..., v + 1, After...>{};
}

// demonstrate of usage

template<int v>
struct A {};

template<typename T, int v>
struct B {};

/// call enum_to_type to get next type
/// note: the following does not compile
using next_A = decltype(enum_to_type<int, 0, A>()); 
// == A<1>
template<typename T>
using next_B = decltype(enum_to_type<int, T, 0, B>()); 
// == B<1>


The purpose of this function is to write generic code that could make use of non-type template parameter v to construct template class from class template U without the knowledge of how the template parameters are declared in U. Otherwise, one has to write this function for different signatures e.g., U<T v>, U<typename, T v>, U<T v, typename>, and so on.

Edit: I guess what I want is likely not possible.

6
  • Please demonstrate the code that "works". I don't see a way to eliminate Before... and make the above code work; you'll still be trying to pass U after a parameter pack, which is a no-go as far as I know. Commented May 16, 2019 at 3:02
  • 1
    @Yakk-AdamNevraumont I just updated the question with some usage case Commented May 16, 2019 at 3:34
  • You have failed to provide the code that "works" despite being explicitly asked for it. Please @ ping me when you provide the variant you claim "works" that involves removing Before... while leaving After.... After fixing typos and removing Before, it fails to compile: coliru.stacked-crooked.com/a/41ccc50702c56798 Commented May 16, 2019 at 3:41
  • "The purpose of this function is to write generic code that could make use of non-type template parameter v to construct template class from class template U without the knowledge of how the template parameters are declared in U." That is not a thing which is possible in C++. Commented May 16, 2019 at 3:59
  • @Yakk-AdamNevraumont I am afraid you are right. I found that it "worked" because I declared my template U as U<T, typename =void> for SFAINE, in which case it fails with U<T>. Sorry for the confusion, and thanks for the answers. Commented May 16, 2019 at 4:12

1 Answer 1

2

It is possible with some modifications:

//type container template
template<typename...>
struct types{};
//declaration
template<typename ,auto V, typename, template<typename ,decltype(V), typename...>class>
class enum_to_type;
//generic definition
template<typename First, typename ... Befors, First V, typename ... Afters, template<typename ,First, typename...>class U>
class enum_to_type<types<First, Befors...>, V, types<Afters...>, U>{
public:
    static auto go(){
        return U<types<Befors...>, V + 1, Afters...>{};
    }
};
//specialization
template<auto V, typename ... Afters, template<typename ,decltype(V), typename...>class U>
class enum_to_type<types<>, V,types<Afters...>, U>{
public:
    static auto go(){
        return U<types<>, V + 1, Afters...>{};
        //or
        //return U<types<>, V, Afters...>{};
    }
};
//Declarations and specializations for the target class templates
template<typename, int>
struct A{};

template<typename, int, typename>
struct B;
template<typename T, int V>
struct B<types<>, V, T > {};

using next_A = decltype(enum_to_type<types<int>,  0, types<>, A>::go());

template<typename T>
using next_B = decltype(enum_to_type<types<int>, 0, types<T>, B>());

template<typename, auto, typename...>
struct general_case;
template<typename ... befors, int V, typename ... afters>
struct general_case<types<befors...>, V, afters ...> {};

Usage:

decltype(enum_to_type<types<>,  0, types<>, A>::go()) object_A;
decltype(enum_to_type<types<>, 0, types<int>, B>::go()) object_B;
decltype(enum_to_type<types<int, float>, 3, types<int>, general_case>::go()) object_general;

It is just that compiler does not have a way to find out how many types are in before and after. That is why in general it can take only one arguments pack in template declaration. But it can handle multiple arguments packs in specialization!

Good luck!

Sign up to request clarification or add additional context in comments.

6 Comments

It is a shame that same thing can not be done for function templates, because non type non variable specialization for function templates are not allowed!
If you use auto, First is no longer needed.
Whereas changing enum_to_type seems acceptable, you also change input classes A and B...
@Jarod42 You are right. I missed some points and thank you for reminding me. And here, I updated the code and now it is OK. And yes definitely the interfacing of the templates has to change!
Thank you very much for the answer. This is great!
|

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.