Disabling a constructor using std::enable_if

Disabling a constructor using std::enable_if

Problem Description:

My aim is to create my own analogue of std::basic_string but with some additional conditions. I want my AnyString<CharType, Traits> to be convertible from std::basic_string<CharType, AnyOtherTraits, AnyAlloc> but I want to disable this constructor for some CharType such that basic_string<CharType> does not exist (compile).

I tried to do something like that:

    template<typename OtherTraits, typename Alloc, typename = 
        std::enable_if_t<!std::is_array_v<char_type> && 
        std::is_trivial_v<char_type>                 && 
        std::is_standard_layout_v<char_type>>>
    AnyString(const std::basic_string<char_type, OtherTraits, Alloc>&);

And I have ColouredChar, which does not meet the conditions listed inside enable_if_t.

Now, when I’m trying to call the disabled constructor :

std::basic_string<ColouredChar> de("string"_purple);
ColouredString d(de);

I do not only get the compile errors from basic_string but also very strange one, telling me that completely different PRIVATE constructor constructor cannot convert its parameter from basic_string.

Is there any way to make these compile errors more readable? Or at least explain whether there’s anything here to worry about.

Solution – 1

Basic example for constructor restriction using concepts (not your traits)

#include <type_traits>
#include <string>

// declare your own concept
template<typename type_t>
concept my_concept = std::is_convertible_v<type_t, std::string>; // just a demo concept
    
class ColouredString
{
public:
    // then you can limit your constructor to types satisfying that concept
    ColouredString(const my_concept auto& /*arg*/)
    {
    }

    ~ColouredString() = default;
};


int main()
{
    // ColouredString str{ 1 };
    ColouredString str{ "hello world!" };

    return 0;
}

Solution – 2

just to point out, in addition to exist answer, you don’t need to define a concept to use it in require-clause

class ColouredString{
public:
    template<typename T>
    requires (std::is_convertible_v<T, std::string>)
    ColouredString(const T&){}
};

and there is already a std::convertable_to concept

class ColouredString{
public:
    ColouredString(const std::convertible_to<std::string> auto&){}
};


fwiw, since you said

I want to disable this constructor for some CharType such that basic_string does not exist

your code fail with string constructor probably simply because you try to create one. it has nothing with ColouredString

std::basic_string<ColouredChar> de("string"_purple); // it already fail here
ColouredString d(de); 
Rate this post
We use cookies in order to give you the best possible experience on our website. By continuing to use this site, you agree to our use of cookies.
Accept
Reject