Home > Net >  How can I resolve Error: variable template-id 'complex type' in nested-name-specifier
How can I resolve Error: variable template-id 'complex type' in nested-name-specifier

Time:08-24

First, let's define the problem. We have a lot of class types in a larger project. A bunch of these types are code-gened by a tool we don't control the output for. This means we can't control their inheritance chain, and their implementations may be very complex. There is also existing tooling for rolling out these types intelligently using macros to build complex structures like complex switch case statements, and other repetitive implementations where templates just won't cut it. BUT I want some extra resiliency and safety of the type system wherever possible. Thus I also want to be able to utilize TypeLists, and type_traits with static assertions to restrict certain interfaces with clear, readable error messages. However, I am having a lot of trouble writing the code that groups these types into clusters, and I don't understand the error, which is mentioned in the title. I am giving this context in case I am running up against an obvious X Y problem, but this has seemed the most promising path so far that I have found.

Here's a simplified version of the code so far, I commented out certain includes so that you can just copy paste this as one block for testing, but left them as comments so you can get an idea of how this should link in a real example. I also excluded header guards for brevity, but assume the headers would have standard header guards:

    // AStruct.hpp
    // special group of 'A' structs (assume these are complex types and we can't control their inheritance chain)
    struct A0{};
    struct A1{};
    struct A2{};
    struct A3{};
    struct A4{};
    struct A5{};
    struct A6{};
    struct A7{};
    struct A8{};
    struct A9{};
    
    // BStruct.hpp
    // special group of 'B' structs (assume these are complex types and we can't control their inheritance chain)
    struct B0{};
    struct B1{};
    struct B2{};
    struct B3{};
    struct B4{};
    struct B5{};
    struct B6{};
    struct B7{};
    struct B8{};
    struct B9{};
    
    // TypeList.hpp
    #include <type_traits>
    
    template<typename ... Types>
    struct TypeList;
    
    template<template <typename T, typename U> typename Evaluator, typename Term, typename Head, typename ... Tail> struct OneOf;
    
    template<template <typename T, typename U> typename Evaluator, typename Term, typename Head> struct OneOf<Evaluator, Term, TypeList<Head> >
    {
        using value = std::bool_constant<Evaluator<Term, Head>::value>;
    };
    template<template <typename T, typename U> typename Evaluator, typename Term, typename Head, typename ... Tail> struct OneOf<Evaluator, Term, TypeList<Head, Tail...> >
    {
        using value = std::bool_constant<Evaluator<Term, Head>::value || OneOf<Evaluator, Term, TypeList<Tail...> >::value>;
    };
    
    template<template <typename T, typename U> typename Evaluator, typename Term, typename Head, typename ... Tail >
    inline constexpr bool OneOfV = OneOf<Evaluator, Term, TypeList<Head, Tail...> >::value;
    
    // AStructUtils.hpp
    // #include TypeList.hpp
    // #include AStruct.hpp
    
    // This is setup as a macro so that other macros can consume it in addition
    // to templates with TypeList
    #define A_STRUCT_TYPES \
    A0, \
    A1, \
    A2, \
    A3, \
    A4, \
    A5, \
    A6, \
    A7, \
    A8, \
    A9
    
    template<typename AStruct>
    using AStructTypes = TypeList <A_STRUCT_TYPES>;
    
    template< typename AStruct >
    inline constexpr bool IsAStructV = OneOfV<std::is_same, AStruct, AStructTypes >::value;
    
    // BStructUtils.hpp
    // #include TypeList.hpp
    // #include BStruct.hpp
    
    // This is setup as a macro so that other macros can consume it in addition
    // to templates with TypeList
    #define B_STRUCT_TYPES \
    B0, \
    B1, \
    B2, \
    B3, \
    B4, \
    B5, \
    B6, \
    B7, \
    B8, \
    B9
    
    template<typename BStruct>
    using BStructTypes = TypeList <B_STRUCT_TYPES>;
    
    template< typename BStruct >
    inline constexpr bool IsBStructV = OneOfV<std::is_same, BStruct, BStructTypes >::value;
    
    // Driver main.cpp includes
    // #include AStructUtils.hpp
    // #include BStructUtils.hpp
    #include <string>
    #include <iostream>
    
    int main()
    {
        std::string buffer;
        buffer.append( "A4 is a AStruct type: "   std::to_string( IsAStructV<A4> )   "\n" ); // 1
        buffer.append( "B4 is a AStruct type: "   std::to_string( IsAStructV<B4> )   "\n" ); // 0
        buffer.append( "A4 is a BStruct type: "   std::to_string( IsBStructV<A4> )   "\n" ); // 0
        buffer.append( "B4 is a BStruct type: "   std::to_string( IsBStructV<B4> )   "\n" ); // 1
        std::cout << buffer << std::flush;
    }

And here's the full error:

:68:36: error: variable template-id 'OneOfV struct std::is_same, AStruct, template using AStructTypes = TypeList >' in nested-name-specifier

Here's the example in GodBolt: https://godbolt.org/z/Mber5YToY

CodePudding user response:

It's a bit unusual to alias a type as value. Instead, I recommend you declare it as a static member so that you can directly extract it using a variable template.

template<template <typename T, typename U> typename Evaluator, typename Term, typename Head, typename ... Tail> struct OneOf;

template<template <typename T, typename U> typename Evaluator, typename Term, typename Head> struct OneOf<Evaluator, Term, TypeList<Head> >
{
    static inline constexpr bool value = std::bool_constant<Evaluator<Term, Head>::value>::value;
};
template<template <typename T, typename U> typename Evaluator, typename Term, typename Head, typename ... Tail> struct OneOf<Evaluator, Term, TypeList<Head, Tail...> >
{
    static inline constexpr bool value = Evaluator<Term, Head>::value || OneOf<Evaluator, Term, TypeList<Tail...> >::value;
};

The template parameters of variable template OneOfV should be the exact same as Oneof in your case.

template<template <typename T, typename U> typename Evaluator, typename Term, typename Head, typename ... Tail >
inline constexpr bool OneOfV = OneOf<Evaluator, Term, Head, Tail...>::value;

Otherwise, IsAStructV<A4> will expand to OneOf<std::same_as, A4, TypeList<AStructTypes>>::value, of which the third parameter is expected to be AStructTypes.

Also, there's no reason for AStructTypes to be a template. It's a determined type. So is BStructTypes.

using AStructTypes = TypeList <A_STRUCT_TYPES>;

Demo

  • Related