Refactoring Code to assert at compile time instead of throwing an exception at runtime

  assert, c++, c++17, static-assert, throw

Consider the following code example, a simple template class wrapper with basic overloaded arithmetic operators. In this class’s operator/ I’m using the ternary operator to throw an exception if division by 0 is detected otherwise, I’m returning the calcuation.

some.h

#pragma once

#include <cassert>
#include <stdexcept>

template<typename T>
struct Var {
    T var;
   
    // ... other operators
 
    const auto operator/(const Var& rhs) {        
        return ((rhs.var == 0) ? throw std::exception("Division by 0") : (var / rhs.var));
    }
};

Here’s the driver program:

#include <iostream>

#include "some.h"

int main() {
    try {
        Var<int> t1{ 4 };
        Var<int> t2{ 0 };
        auto t3 = t1 / t2;
        std::cout << t3 << 'n';
    } catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    } catch (...) {
        std::cerr << "Unknown Exceptionn";
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

And this will compile and build and when we run it (I’m using Visual Studio), it will throw an exception giving this message to the console

Division by 0

C:Users...sourcereposData Structure Samplesx64DebugData Structure Samples.exe (process 8756) exited with cod
e 1.
To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the conso
le when debugging stops.
Press any key to close this window . . .

Okay, this is simple enough and it works.


Let’s say that I want to refactor this code with two primary objectives:

  • First, Abstract the Operators away from the class
  • Don’t want to throw an exception, but would rather assert at compile time.

The class would transform into this:

some.h

#pragma once

#include <cassert>
#include <stdexcept>

template<typename T>
struct Var {
    T var;
};

// ... other operators

template<typename T>
const auto operator/(const Var<T>& lhs, const Var<T>& rhs) {
    static_assert(rhs.var != 0, "Division by 0!");

    return (lhs.var / rhs.var);
}

However, this is failing to compile with these generated errors…

1>------ Build started: Project: Data Structure Samples, Configuration: Debug x64 ------
1>main.cpp
1>c:users...sourcereposdata structure samplesdata structure samplesdatastructs.h(25): error C2131: expression did not evaluate to a constant
1>c:users...sourcereposdata structure samplesdata structure samplesdatastructs.h(25): note: failure was caused by a read of a variable outside its lifetime
1>c:users...sourcereposdata structure samplesdata structure samplesdatastructs.h(25): note: see usage of 'rhs'
1>c:users...sourcereposdata structure samplesdata structure samplesmain.cpp(15): note: see reference to function template instantiation 'const auto operator /<int>(const Var<int> &,const Var<int> &)' being compiled
1>Done building project "Data Structure Samples.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

I can easily enough use assert at runtime without any problems, however, I’m struggling to figure out how to use static_assert properly within this context. What am I doing wrong, what am I missing here? I’ve searched online for various use case examples of static_assert but haven’t found anything suitable. Even if I move the operators back inside of the class and try to use static_assert I still end up with very similar error messages.

Source: Windows Questions C++

LEAVE A COMMENT