0

I have coded a class:

template<unsigned int N>
class WrappedUInt {
    unsigned int m_value;
public:
// Many methods to imitate the unsigned integer type
// This class works as a interface (except for `N==0 || N==1`)
};

template<> class WrappedUInt<0> : public std::false_type {};
template<> class WrappedUInt<1> : public std::true_type {};

Then I have defined a variant type for an aplicattion:

using wuint_64_variant = std::variant<
    WrappedUInt<0>,WrappedUInt<1>,WrappedUInt<2>,WrappedUInt<3>,WrappedUInt<4>,WrappedUInt<5>,
    // to complete this large list with step 1
    WrappeUInt<60>,WrappeUInt<61>,WrappeUInt<62>,WrappeUInt<63>
>;

Now I need functions for this variant type. I use a switch/case statement to work with this. It works very pretty with 2, 3, 4, ... , 63 distint cases in the statement.

I have read that the g++ compiler has limited the number of cases to 200, as clang++, MSVC and Intel compilers to 256, and the recomendation of standard is a minimum of 16384.

But gcc fails with more than 63 cases plus the default case, with the error 'File too big', why?

And other question is can I increment the number of cases permitted in a switch statement?

Earendil
  • 23
  • 5
  • I doubt that this has anything to do with the `switch` itself. This sounds to me like you instantiate too many function templates, so that the binary becomes larger than the linker can handle. Please try to provide a [mre]. – user17732522 May 06 '23 at 14:29
  • Also, why do you need a `switch` with a `variant`? `std::visit` already handles that internally (and potentially more efficiently). – user17732522 May 06 '23 at 14:30
  • Seems like quite the logical leap to go from "file too big" to "too many cases". Do you have any evidence to back up this conclusion? The only test that comes to my mind is replacing the last few cases with an `if-else-if` tree, and having the problem go away even though the exact same cases are covered (and even that test I find more suggestive than conclusive). – JaMiT May 06 '23 at 15:05
  • 1
    Does this answer your question? [Maximum number of cases that can be addressed using switch statement](https://stackoverflow.com/questions/20355948/maximum-number-of-cases-that-can-be-addressed-using-switch-statement) Note that [this answer](https://stackoverflow.com/a/20356073) disputes your claim that gcc and MSVC impose limits lower than what can be handled based on available memory. – JaMiT May 06 '23 at 15:10

1 Answers1

1

I agree with @JaMIT that this is unlikely due to a compiler switch statement limitation. Also mentioned by @user17732522 in the comments, if you have a std::variant, there are more efficient options for dispatching. The following match function allows you to write readable and efficient code for dispatching on type (including auto as a catch-all) for a std::variant.

Use

match(try_value,
    [](const TrySuccess<int>& value) {
        cout << "The Try contained the value " << value.get() << endl;
    },
    [](const TryFailure& fail) {
        cout << "Try Try contained a failure"
    });

Definition

#pragma once
#include <variant>

namespace core {
inline namespace utility {

template<class... Ts>
struct overloaded : Ts... {
    using Ts::operator()...;
};

template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;

/// Pattern match a `std::variant` derived type against its contained type.
///
/// \tparam T The variant type
/// \tparam Us... The lambda types
///
/// \verbatim embed:rst:leading-slashes
///
/// ```{code-block} cpp
/// match(try_value,
///     [](const TrySuccess<int>& value) {
///         cout << "The Try contained the value " << value.get() << endl;
///     },
///     [](const TryFailure& fail) {
///         cout << "Try Try contained a failure"
///     });
/// ```
///
/// \endverbatim
///
template<class T, class... Us>
auto match(T&& variant, Us&&... handlers) {
    return std::visit(overloaded{std::forward<Us>(handlers)...}, std::forward<T>(variant));
}

}; // utility
}; // core
RandomBits
  • 4,194
  • 1
  • 17
  • 30