3
\$\begingroup\$

What follows is a simplified version of a tentative implementation for a template-based set, named TemplateArgs. For the sake of clarity and focus on the question at hand, TemplateArgs was converted into a non-parameterized class, and its size and elements are hard-coded. It should be C++11-compliant and portable (any OS, any compiler, any architecture, etc).

My question is about std::array::operator[]. Because it is non-constexpr, one needs to use std::get() instead to achieve constexpr-ness, unless a C++14 compiler is used.

#include <array>
#include <iostream>
#include <climits>

// Some recursion witchcraft
template <typename T, size_t size, size_t index = size - 1>
struct StdArrayContains_ {
    constexpr static inline bool contains(T elem, const std::array<T, size>& array) {
        return std::get<index>(array) == elem || StdArrayContains_<T, size, index - 1>::contains(elem, array);
    }
};
template <typename T, size_t size>
struct StdArrayContains_<T, size, 0> {
    constexpr static inline bool contains(T elem, const std::array<T, size>& array) {
        return std::get<0>(array) == elem;
    }
};

struct TemplateArgs {
    constexpr static size_t size = 4;

    // Some query/getter methods
    constexpr static std::array<int, size> values() {
        return {1, 2, 3, 4};
    }
    constexpr static bool contains(int elem) {
        return StdArrayContains_<int, size>::contains(elem, values());
    }

    // Some methods used for testing
    template <typename CharT, typename CharTraits>
    static inline std::basic_ostream<CharT, CharTraits>& 
    print(std::basic_ostream<CharT, CharTraits>& os) {
        os << "Size: " << size << std::endl;
        os << "Elements: {";
        const char* sep = "";
        for (auto& elem : values()) {
            os << sep << elem;
            sep = ", ";
        }
        os << "}" << std::endl;
        return os;
    }
    template <typename CharT, typename CharTraits>
    static inline std::basic_ostream<CharT, CharTraits>& 
    printContains(int elem, std::basic_ostream<CharT, CharTraits>& os) {
        os 
            << "Contains the element '" << elem << "'? "
            << contains(elem) << std::endl;
        return os;
    }
};

int main(void) {
    constexpr int validElem = 2, invalidElem = 5;

    static_assert( TemplateArgs::contains(validElem), "");
    static_assert(!TemplateArgs::contains(invalidElem), "");

    // Testing
    std::cout << std::boolalpha;
    TemplateArgs::printContains(validElem, std::cout);
    TemplateArgs::printContains(invalidElem, std::cout);
    TemplateArgs::print(std::cout);

    return 0;
}

The implementation works (compiles and executes without errors or warnings), but I'm wondering if I'm letting anything pass by, or if there is anything that's not allowed by the standard. For example:

  • Is TemplateArgs::contains() truly constexpr? The argument to the function elem is not constexpr itself, but is being passed around in a lot of constexpr code.
  • Is there any better option that's C++11-compliant (for example, implement a fully constexpr std::array, although I failed miserably at that)?

This is my system, by the way:

[flisboac@sonic ~]$ g++ -v && uname -a && lsb_release -a
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/6.2.1/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc-multilib/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --enable-multilib --disable-werror --enable-checking=release
Thread model: posix
gcc version 6.2.1 20160830 (GCC) 
Linux sonic 4.8.13-1-ARCH #1 SMP PREEMPT Fri Dec 9 07:24:34 CET 2016 x86_64 GNU/Linux
LSB Version:    1.4
Distributor ID: Arch
Description:    Arch Linux
Release:    rolling
Codename:   n/a

The whole template-based set's implementation is here, if anyone is curious to see.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.