Home > OS >  How can I define different struct members for different template parameters?
How can I define different struct members for different template parameters?

Time:08-03

How can I define different struct members for different template parameters? I've tried to use the requires keyword the following way:

template<typename T> requires std::is_void_v<T>
class Foo
{
public:
    void Bar()
    {
    }
};
template<typename T>
class Foo
{    
public:
    T* Bar()
    {
        if (!m_T)
            m_T = new T();
    
        return m_T;
    }

private:
    T* m_T{};
};

But this does not compile:

  1. Foo<T> Foo(void): could not deduce template argument for T
  2. Foo<T> Foo(Foo<T>): expects 1 argument - 0 provided
  3. Foo: requires clause is incompatabile with the declaration

Is this behaviour even possible in C 20?

CodePudding user response:

While requires may be useful in general, its advantages for exactly matching one template parameter type are outweighed by the negatives.

Template specialization of types has been possible since C 03, maybe even C 98:

template<typename T>
class Foo;

template<>
class Foo<void>
{
public:
    void Bar()
    {
    }
};

template<typename T>
class Foo<T>
{    
public:
    T* Bar()
    {
        if (!m_T)
            m_T = new T();
    
        return m_T;
    }

private:
    T* m_T{};
};

In order to use concepts, you should still follow the same overall pattern:

  1. Declare the template
  2. Define the specializations

Example assuming my_is_magic_v is a fancier concept, not just a single particular type.

template<typename T>
class Foo;

template<typename T> requires my_is_magic_v<T>
class Foo<T>
{
public:
    void Bar()
    {
    }
};

template<typename T>
class Foo<T>
{    
public:
    T* Bar()
    {
        if (!m_T)
            m_T = new T();
    
        return m_T;
    }

private:
    T* m_T{};
};

CodePudding user response:

Regarding the third error:

You cannot declare two primary class templates with the same name in the same scope. You can only declare one primary template and then add partial or explicit specializations for it. Partial specializations need to be more specialized than the primary template.

The syntax for a partial specialization is slightly different than what you are using (the syntax for primary templates) and a declaration of the primary template must precede the partial specialization:

// primary class template
template<typename T>
class Foo
{    
public:
    T* Bar()
    {
        if (!m_T)
            m_T = new T();
    
        return m_T;
    }

private:
    T* m_T{};
};

// partial specialization with (more) constraints
template<typename T> requires std::is_void_v<T>
class Foo<T> // <- Additional template argument list for partial specialization
{
public:
    void Bar()
    {
    }
};

The other error messages are either a consequence of this issue as well or caused by a problem with how the template is used somewhere else that you are not showing.

  • Related