A quick note: you can use C++11 templates to detect struct fields by name and type, and statically branch on them. I first heard of this solution from breeze1990.

Say I want to detect if a struct has a field size of type int. Create two template instantiations of the same name, here HasStaticSize that defaults to false.

#include <type_traits>

template <typename T, typename = void>
struct HasStaticSize : std::false_type {};

template <typename T>
struct HasStaticSize<
    T, typename std::enable_if<
           std::is_same<int, std::decay_t<decltype(T::size)>>::value,
           void>::type> : std::true_type {};

The latter is only resolved if T::size is declared as int, or more specifically, something that “decays” to int. The outcome of these two is inheriting from structs whose ::value member is constant true or false.

Then you can use constexpr in an if to branch on the check (::value extracts a boolean member from the templated struct), and behave differently based on the result.

struct Foo {
    static constexpr int size = 7;
};

int wat() {
    if constexpr (HasStaticSize<Foo>::value) {
        return 0;
    }
    return 1;
}

Godbolt link, which shows the compiled code only has one branch, either returning 0 or 1 based on whether the field name resolves and the type matches.

Note removing the decay_t will change the result, because apparently decay removes const. You could also remove it and compare to const int.

This is all weird and I don’t really like C++ template metaprogramming.


Want to respond? Send me an email, post a webmention, or find me elsewhere on the internet.

This article is syndicated on:

DOI: https://doi.org/10.59350/82baf-xvw93