Home > database >  dependent types without helper type
dependent types without helper type

Time:06-11

Given typename T and int N, the templated value below generates a null function pointer of the type:

int (*) (T_0, ... T_N)

While the code works, I don't like that it pollutes the namespace with the Temp bootstrap helper - Temp is required because types can't be enclosed in parentheses. For example, none of the following are valid.

(int (*)((int))
((int (*)(int)))
(int (*)( (I,T)... ))

The last entry shows how I would like to expand T into a list of N Ts - which of course isn't valid. It's a trick to make T depend on I but with a value only of T, thanks to the comma operator.

As a workaround, I'm forced to create the one-shot type Temp templated to make T depend on int, or in this case, I. Its usage as Temp<T,I> is valid because it doesn't enclose types in parenthesis.

However, like I said, I want to get rid of Temp because it pollutes the namespace. In the code below I restate the problem and demonstrate some attempted workarounds which sadly, all fail. For the record, I think an equivalence between template <typename T, int> using Temp = T; and template <... template<typename T1, int N1> typename Temp=T> should be allowed.

Followup: When I original published this question, I didn't know exactly why extra parentheses were disallowed, and I'm still not sure why some of my attempts failed. For example:

decltype(w<T,N>())...
result_of<w<T,N>()>::type...

I don't see any parentheses around types!


#include <iostream>
#include <typeinfo>


// Problem, #1
// This is a one-shot helper than pollutes the namespace
template <typename T, int>
using Temp = T;

// Idea #1
//  Make the one-shot helper actuall useful, where ... represents either
//  type or non-type parameters.
// Result
//  Not possible.
//template <typename T, ...>
//using Dependent = T;

// Idea #2
//  Make the types dependent within the template declaration
// Result
//  Probably not possible
//template <typename T, int N, template<typename T1, int N1> typename F=T>

// Idea #6
//  Replace the lambda with a struct (not shown)
// Result
//  Crashes gcc
template <typename T, int N>
auto a =
    []<size_t... I>
    (std::index_sequence<I...>) { 
        // Problem #2
        //  Function type declaration won't parse with extra parentheses
        //return (int (*)( (I,T)... ))nullptr;

        // Idea #3
        //  Move the templated helper into the function
        // Result
        //  Not possible
        //template <typename T, int>
        //using Temp = T;

        // Idea #4
        //  Replace the templated helper with a templated lambda which *is*
        //  allowed inside functions.
        // Result
        //  Still requires parentheses, still breaks function type declaration
        //auto w = []<typename T1, int N1>() -> T1 {};
        //return (int (*)( decltype(w<T,N>())... ));

        // Idea #5
        //  result_of (which is a template) instead of decltype
        // Result
        //  Doesn't work even without parentheses, not sure why
        //return (int (*)( result_of<w<T,N>>... ));
        //return (int (*)( result_of<w<T,N>()>::type... ));

        // Idea #7
        //  Use std::function
        // Result
        //  Can't get function pointer from std::function

        // Idea #2 implementation
        //using F<T,I> = T;
        //return (int (*)( F<T,I>... ))nullptr;

        // So far, only this works:
        return (int (*)( Temp<T,I>... ))nullptr;
    }
    (std::make_index_sequence<N>{});

int main () {
    auto b = a<int, 4>;
    std::cout << typeid(b).name() << std::endl;
}

CodePudding user response:

You can replace Temp<T,I> with std::enable_if_t<(void(I), true), T>.


Function type declarations won't parse extra parentheses

that actually works! Why?

Types can't be enclosed in parentheses. But the first argument of enable_if_t is an expression rather than a type, so ( ) is allowed there.

  • Related