Search code examples
c++c++20c++-concepts

C++20: Unable to properly use concepts to enforce that a constructor template parameter is a base of one of two types


I am a bit of a noob to C++20, and I only recently have been able to use C++11/14 so I am trying to update my knowledge and I'm having a bit of trouble trying to use concept requirements. My goal is to ensure that a class of type SocketAddress only takes a type of IpV4Address or IpV6Address in its constructor, while using a template constructor so that I don't have to have 6 different constructor definitions for passing by value, ref, or r-value.

I am able to compile the class of SocketAddress when it is defined as:

template <typename T>
concept IpAddress = std::is_base_of<IpV4Address, T>::value || std::is_base_of<IpV6Address, T>::value;

class SocketAddress
{
public:

   SocketAddress() = delete;

   template <typename T> requires IpAddress<T>
   SocketAddress(T&& ip_address, const uint16_t port) noexcept;

};

template <typename T> requires IpAddress<T>
SocketAddress::SocketAddress(T&& ip_address, const uint16_t port) noexcept :
   m_ip_address(std::forward<T>(ip_address))   
{

}

However, when I actually attempt to construct a SocketAddress in my tests I get the compiler error:

error C2661: 'CrossPlatformSockets::SocketAddress::SocketAddress': no overloaded function takes 2 arguments

Where my test code is:

SocketAddress socket_address(IpV4Address("127.0.0.1"), 8000);

I'm not really sure what I am missing here such that the compiler is unable to detect the constructor I have defined that takes two inputs. If anyone can help me learn how to use these concepts or point out what is wrong I would greatly appreciate it! I know I could not use concepts, and use some form of static assert/ugly SNFINAE-type solution, however I want to learn the new stuff!


Solution

  • This is dumb but a clean and rebuild literally fixed my problem.

    Additionally given @PatrickRoberts suggestion, my concept is now defined as:

    template <typename T>
    concept IpAddress = std::is_base_of<IpV4Address, std::remove_cvref_t<T>>::value || 
                        std::is_base_of<IpV6Address, std::remove_cvref_t<T>>::value;