How best to implement the “newtype” idiom in C++? [duplicate]

What is the best way to implement the newtype idiom in C++?

Rating the best many times end up in the preferential domain, but you’re already mentioned two alternative approaches yourself: simply custom structs wrapping a value of a common type (say int), or using enum classes with an explicitly specified underlying type for strongly type near-identical types.

If you’re mainly after strongly typed type aliases of a common type, say

struct Number { int value; }

or, a common type with a parameterizable underlying type

template<typename ValueType = int>
struct Number { ValueType value; }

then another common approach (which also facilitates re-using functionality between strongly type-distinct but related types) is making(/expanding) the Number class (template) a class template parameterized over type template tag parameter, such that specializations over the tag types results in strong typing. As pointed out by @Matthieu M., we may declare a struct as part of the template argument list to a given specialization, allowing a lightweight tag declaration and alias tagging in a single alias declaration:

template<typename Tag, typename ValueType = int>
struct Number {
    ValueType value;
    // ... common number functionality.
};

using YearNumber = Number<struct NumberTag>;
using DayNumber = Number<struct DayTag>;

void takeYears(const YearNumber&) {}
void takeDays(const DayNumber&) {}

int main() {
    YearNumber y{2020};
    DayNumber d{5};
    
    takeYears(y);
    //takeDays(y);  // error: candidate function not viable
    
    takeDays(d);
    //takeYears(d);  // error: candidate function not viable
    
    return 0;
}

Note that in case you would like to specialize non-member functions of the Number class template for specific tags (or e.g. use tag dispatch for a similar purpose), you would need to declare the type tags outside of the alias declaration.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)