Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to specialize a type trait using concepts?

I am trying to use C++ concepts in order to write a type trait that will produce a different type depending on whether its template argument is a fundamental type or not:

template<typename T>
concept fundamental = std::is_fundamental_v<T>;

template<typename T>
concept non_fundamental = !std::is_fundamental_v<T>;

The following code works just as expected:

void Print(fundamental auto value)
{
    std::cout << "fundamental\n";
}
void Print(non_fundamental auto value)
{
    std::cout << "non fundamental\n";
}

int main()
{
   Print(1); // prints "fundamental"
   Print(std::string("str")); // prints "non fundamental"
}

Applying the same idea on type traits doesn't work.

template<fundamental T>
struct SomeTypeTrait
{
    using type = T;
};

template<non_fundamental T>
struct SomeTypeTrait
{
    using type = std::shared_ptr<T>;
};


using ExpectedToBeDouble = SomeTypeTrait<double>::type;
using ExpectedToBeSharedPtrOfString = SomeTypeTrait<std::string>::type; // fails to compile

I get a compiler error (MSVC) saying:

error C3855: 'SomeTypeTrait': template parameter 'T' is incompatible with the declaration

How can I achieve the desired behavior using concepts?

like image 517
Elad Maimoni Avatar asked May 14 '26 23:05

Elad Maimoni


1 Answers

Apparently the syntax is slightly different from what I had in mind.

Here is a working solution:

template<typename T>
struct SomeTypeTrait {};

template<fundamental T>
struct SomeTypeTrait<T> // note the extra <T>
{
    using type = T;
};

template<non_fundamental T>
struct SomeTypeTrait<T> // note the extra <T>
{
    using type = std::shared_ptr<T>;
};

Also, one of the specializations could become the default implementation to make the code a bit shorter and allows for more specializations to be added later:

template<typename T>
struct SomeTypeTrait // default
{
    using type = std::shared_ptr<T>;
};

template<fundamental T>
struct SomeTypeTrait<T> // specialization for fundamental types
{
    using type = T;
};
like image 102
Elad Maimoni Avatar answered May 16 '26 11:05

Elad Maimoni