Home > Software design >  How to explicitly instantiate a func template with no parameter?
How to explicitly instantiate a func template with no parameter?

Time:12-03

I have a member func template as following:

using ArgValue_t = std::variant<bool, double, int, std::string>;

struct Argument_t {
    enum Type_e { Bool, Double, Int, String, VALUES_COUNT };

    template<typename T>
    as( const Argument_t& def ) const;

    std::string name;
    ArgValue_t  valu;
    ArgValue_t  maxv;
    ArgValue_t  minv;
    Type_e      type = Int;
    int         prec = 0;
};

// specializing for bool
template<>
bool Argument_t::as<bool>( const Argument_t& def ) const {
    if( static_cast<Type_e>( valu.index() ) != Bool )
        return get<bool>( def.valu );

    return get<bool>( valu );
};

// specializing for double
template<>
double Argument_t::as<double>( const Argument_t& def ) const {
    if( static_cast<Type_e>( valu.index() ) != Double )
        return get<double>( def.valu );

    return min<double>( get<double>( def.maxv ),
                              max<double>( get<double>( def.minv ), get<double>( valu ) ) );
};

// specializing for string
template<>
string Argument_t::as<string>( const Argument_t& def ) const {
    if( static_cast<Type_e>( valu.index() ) != String )
        return get<string>( def.valu );

    return get<string>( valu );
};

// default version for all of integral types
template<typename T>
T Argument_t::as( const Argument_t& def ) const {
    if( static_cast<Type_e>( valu.index() ) != Int )
        return get<T>( def.valu );

    return min<T>( get<T>( def.maxv ),
                        max<T>( get<T>( def.minv ), get<T>( valu ) ) );
};

When I compiling it, I get link error, so I add a few of explicit instantiation of them.

// there is no problem with these three
template string Argument_t::as<string>( const Argument_t& ) const;
template bool Argument_t::as<bool>( const Argument_t& ) const;
template double Argument_t::as<double>( const Argument_t& ) const;

// but these six can **NOT** be compiled
template int8_t  Argument_t::as<int8_t>( const Argument_t& ) const;
template uint8_t  Argument_t::as<uint8_t>( const Argument_t& ) const;
template int16_t  Argument_t::as<int16_t>( const Argument_t& ) const;
template uint16_t  Argument_t::as<uint16_t>( const Argument_t& ) const;
template int32_t  Argument_t::as<int32_t>( const Argument_t& ) const;
template uint32_t  Argument_t::as<uint32_t>( const Argument_t& ) const;

Compiler error message:

/usr/include/c /9/variant: In instantiation of ‘constexpr const _Tp& std::get(const std::variant<_Types ...>&) [with _Tp = signed char; _Types = {bool, double, int, std::__cxx11::basic_string<char, std::char_traits, std::allocator >}]’: Argument.cpp:57:16: required from ‘T octopus::Argument_t::as(const octopus::Argument_t&) const [with T = signed char]’ Argument.cpp:67:53: required from here /usr/include/c /9/variant:1078:42: error: static

assertion failed: T should occur for exactly once in alternatives

Why did I get this? How to resolve it?

CodePudding user response:

I think I found the answer:

The type ArgValue_t is a instance of the template std::variant with arguments: bool/double/int/std::string, but NOT with int8_t/uint8_t/int16_t/uint16_t/... as arguments, therefore in the invokations of get(), it only can accept bool/double/int/std::string as template arg.

Thank you all gentlemen, Especially @Jarod42!!!

May I complain the message of gcc? At least it may warn me the template-arg of get() is incorrect?

  • Related