Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatic type deduction using is_same_v

Tags:

c++

templates

I have some code in a template like so:

if constexpr ( std::is_same_v<T, CompletedGeneration> ) {
    auto stat = stats->getGenerationStats();
} else if constexpr ( std::is_same_v<T, CompletedReset> ) {
    auto stat = stats->getResetStats();
} else if constexpr ( std::is_same_v<T, CompletedRun> ) {
    auto stat = stats->getRunStats();
} else {
    static_assert( false, "Invalid type for helper function" );
}

The auto for stat was just to get it to compile temporarily. stats is of type T

After this if-statement, there's a bunch of code which relies on stat, so obviously I can't define it in the if portion. I'm wondering, how would I go about defining it outside of the if, since its type is dependent on the template parameter type T (but is not a T itself)?

Would I have to specify an additional template parameter U, which takes in the type for stat? Or have to use some sort of inheritance? Both of these options I'd rather avoid.

like image 390
ChrisMM Avatar asked Dec 13 '22 09:12

ChrisMM


2 Answers

You could wrap it in an immediately invoked lambda expression

auto stat = [&] {
    if constexpr ( std::is_same_v<T, CompletedGeneration> ) {
        return stats->getGenerationStats();
    } else if constexpr ( std::is_same_v<T, CompletedReset> ) {
        return stats->getResetStats();
    } else if constexpr ( std::is_same_v<T, CompletedRun> ) {
        return stats->getRunStats();
    }
}();

This also eliminates the need for the ill-advised static_assert(false), which is now replaced by stat having the invalid type of void.

like image 64
StoryTeller - Unslander Monica Avatar answered Dec 15 '22 23:12

StoryTeller - Unslander Monica


You could use a type trait:

template <typename T>
struct stats_type;

template <>
struct stat_type<CompletedGeneration> {
    using type = decltype(std::declval<T>().getGenerationStats());
};

// and similar for the other cases

The correct type for stat is then just stat_type<T>::type;

However, this is perhaps a bit old-school and too much boilerplate. I just wanted to mention it for the sake of completeness. On the other hand if you wrap the corresponding function call in the constructor of stat_type then you can replace your whole constexpr if-else with a single line of stats_type<T>::type stat{stats};.

like image 34
463035818_is_not_a_number Avatar answered Dec 15 '22 21:12

463035818_is_not_a_number