c++gccstdany

compilation failure with std::any and multiply function


https://godbolt.org/z/hxaq93ebc

The multiply function of double and int fails to compile. I am not sure why it is happening. I tried it on with different compilers, but it didn't work. It appears something else is missing here. I tried with other operators, looks like with multiplication is not working.

Full code:


#include <iostream>
#include <any>
#include <stdexcept>
#include <typeinfo>

struct GenericBinaryOperation {
    template <typename Func>
    std::any operator()(const std::any& lhs, const std::any& rhs, Func&& func) const {
        // Handle integer and double operation
        if (lhs.type() == typeid(int) && rhs.type() == typeid(double)) {
            return func(std::any_cast<int>(lhs), std::any_cast<double>(rhs));
        } else if (lhs.type() == typeid(double) && rhs.type() == typeid(int)) {
            return func(std::any_cast<double>(lhs), std::any_cast<int>(rhs));
        }
        // Handle double and double
        else if (lhs.type() == typeid(double) && rhs.type() == typeid(double)) {
            return func(std::any_cast<double>(lhs), std::any_cast<double>(rhs));
        }
        // Handle integer and integer
        else if (lhs.type() == typeid(int) && rhs.type() == typeid(int)) {
            return func(std::any_cast<int>(lhs), std::any_cast<int>(rhs));
        }
        // Handle string and string (e.g., concatenation)
        else if (lhs.type() == typeid(std::string) && rhs.type() == typeid(std::string)) {
            return func(std::any_cast<std::string>(lhs), std::any_cast<std::string>(rhs));
        } else {
            throw std::invalid_argument("Unsupported or mismatched types");
        }
    }
};

int main() {
    GenericBinaryOperation operation;

    // Integer and double addition
    std::any a = 5;
    std::any b = 3.5;
    auto add = [](auto x, auto y) { return x + y; };
    std::cout << "Add (int + double): " << std::any_cast<double>(operation(a, b, add)) << std::endl;

    // Double and integer multiplication
    std::any c = 2.5f;
    std::any d = 4;
    auto multiply = [](auto x, auto y) { return x * y; };
    std::cout << "Multiply (double * int): " << std::any_cast<double>(operation(c, d, multiply)) << std::endl;

    // String concatenation
    std::any e = std::string("Hello, ");
    std::any f = std::string("World!");
    auto concatenate = [](auto x, auto y) { return x + y; };
    std::cout << "Concatenate (string + string): " << std::any_cast<std::string>(operation(e, f, add)) << std::endl;

    // Example of mismatched types causing an exception
    try {
        std::any g = 42;
        std::any h = std::string("Forty-Two");
        operation(g, h, add); // This will throw an exception due to type mismatch
    } catch (const std::invalid_argument& ex) {
        std::cerr << "Error: " << ex.what() << std::endl;
    }

    return 0;
}

Solution

  • The issue is that there's a path in your function that can ultimately try to call std::string * std::string. The fact your example doesn't do that is irrelevant, since the compiler still has to consider that path through your function.

    If you really need this level of generality, you can add type checks to your lambda. These would be runtime checks, not compile time, but that's probably the best you can do unless somebody much smarter than me has a more clever solution.