woboq / verdigris

Qt without moc: set of macros to use Qt without needing moc
https://woboq.com/blog/verdigris-qt-without-moc.html
GNU Lesser General Public License v3.0
638 stars 58 forks source link

Idea: Better Compiletime Counting #58

Closed arBmind closed 5 years ago

arBmind commented 5 years ago

The compile time counter is used to differentiate and collect the bits of information provided by the macros.

Idea: https://godbolt.org/z/S5WAMH

What do you think?

ogoffart commented 5 years ago

Interesting idea.

COUNTER is a compiler extension, i've tried to stay away from non standard things, but I guess if every compiler support that it could be fine. Maybe COUNTER can be replaced by some unique type or something. COUNTER might not work with templates as the same COUNTER will be re-used for different instantiation. (I guess that's fine if count() and example() are also part of the template.)

if constexpr is c++17, and i'd like to keep supporting C++14 for now, but i guess it can be replaced by good old SFINAE

arBmind commented 5 years ago

It's also possible to do log2 search:

template<size_t L, size_t N = 0, size_t M = 1024, size_t X = (N+M)/2>
constexpr auto count() {
    if constexpr (N==X) {
        return std::is_same_v<void, decltype(example(index<X>))> ? N : M;
    }
    else if constexpr (std::is_same_v<void, decltype(example(index<X>))>) {
        return count<L, N, X>();
    } 
    else {
        return count<L, X, M>();
    }
}

(Godbolt short links seems down)

arBmind commented 5 years ago

A C++14 variant that reduces the MSVC output in Godbolt.

template<size_t L, size_t N, size_t M, size_t X = (N+M)/2
    , bool noX = std::is_same<void, decltype(example(index<X>))>::value
    , bool up = N==X>
struct Count;

template<size_t L, size_t N, size_t M, size_t X>
struct Count<L, N, M, X, true, true> {
    static constexpr auto value = N;
};
template<size_t L, size_t N, size_t M, size_t X>
struct Count<L, N, M, X, false, true> {
    static constexpr auto value = M;
};
template<size_t L, size_t N, size_t M, size_t X>
struct Count<L, N, M, X, true, false> {
    static constexpr auto value = Count<L, N, X>::value;
};
template<size_t L, size_t N, size_t M, size_t X>
struct Count<L, N, M, X, false, false> {
    static constexpr auto value = Count<L, X, M>::value;
};

template<size_t L>
constexpr auto count = Count<L, 0, 1024>::value;

Just to keep track of it 😎

arBmind commented 5 years ago

I did a full implementation for Verdigris. See: https://github.com/arBmind/verdigris/tree/feature/cpp17_forwardCounter

It works at least on GCC 7.3. Visual Studio runs into complexity barriers with my string implementations (same as before).

arBmind commented 5 years ago

This is merged… 👍