0

I have a template class called Basis, instantiated like this:

Basis<std::function<sla::col<3>(const sla::col<2>&)>> basis;

and defined like this:

template<typename V>
struct Basis {
    std::vector<V> vectors;

    Basis()
    {}

    explicit Basis(std::vector<V>&& vectors)
        : vectors(vectors)
    {}

    // if V+=V and V*=double are defined   *** THE FOLLOWING LINE GENERATES THE COMPILER ERROR ***
    template<typename T = std::remove_reference_t<decltype(std::declval<V&>() += (std::declval<V&>() *= double()))>>
    V operator*(const std::vector<double>& coeffs) const {
        V result = zero<V>();
        if (coeffs.size() > vectors.size()) {
            throw std::runtime_error("coeffs count exceeds basis vectors count");
        }
        for (size_t k = 0; k < coeffs.size(); k++) {
            V term = vectors[k];
            term *= coeffs[k];
            result += term;
        }
        return result;
    }

    // alternative to operator* if V does not define += and *=
    LinearCombination<V> linearCombination(const std::vector<double>& coeffs) const {
        LinearCombination<V> result;
        if (coeffs.size() > vectors.size()) {
            throw std::runtime_error("coeffs count exceeds basis vectors count");
        }
        for (size_t k = 0; k < coeffs.size(); k++) {
            result += typename LinearCombination<V>::Term{ coeffs[k], vectors[k] };
        }
        return result;
    }

    // if V(x) is defined
    template<typename X>
    auto operator()(X x) const -> Basis<std::remove_reference_t<decltype(std::declval<V>()(x))>> {
        return Basis<std::remove_reference_t<decltype(std::declval<V>()(x))>>(util::transformation(vectors, [x](const V& v) {
            return v(x);
        }));
    }

    // if V[i] is defined
    template<typename I>
    auto operator[](I i) const -> Basis<std::remove_reference_t<decltype(std::declval<V>()[i])>> {
        return Basis<std::remove_reference_t<decltype(std::declval<V>()[i])>>(util::transformation(vectors, [i](const V& v) {
            return v[i];
        }));
    }
}

It compiles fine with MSVC, but when compiling with GCC I get the following error:


In instantiation of ‘struct Basis<std::function<sla::col<3>(const sla::col<2>&)> >’:
[LINE_NUMBER_OF_INSTANTIATION]:   required from here
[LINE_NUMBER_OF_DECLARATION_OF_OPERATOR*=]: error: no match for ‘operator*=’ (operand types are ‘std::function<sla::col<3>(const sla::col<2>&)>’ and ‘double’)
    template<typename T = std::remove_reference_t<decltype(std::declval<V&>() += (std::declval<V&>() *= double()))>>

Why would GCC be instantiating Basis<std::function<sla::col<3>(const sla::col<2>&)>>::operator* given that std::function<sla::col<3>(const sla::col<2>&)>::operator*= is not defined?

Does the error message imply that GCC thinks basis.operator*() is being invoked somewhere?

I could only find references to members basis.operator()(), basis.linearCombination(). But when I isolate code with only those references, the problem disappears. For this reason I have been unable to isolate a minimal complete example to reproduce the problem for this question, as I have no idea where the problem is actually coming from.

I'm just hoping for any pointers that could lead me in the right direction, on what might be causing the problem.

Museful
  • 6,711
  • 5
  • 42
  • 68
  • 1
    Please add a few lines of code that are needed to turn what's shown into a [mre], that anyone can cut/paste ***exactly as shown***, then compile and produce the same compilation error you're asking about. Right now, the shown code is missing header file inclusions, and whatever ends up instantiating the template. – Sam Varshavchik Jun 14 '20 at 01:20
  • @SamVarshavchik Your request is of course only reasonable, but please see the paragraph before my last paragraph. I have so far been [unable](http://cpp.sh/5rroc) to find and isolate the lines causing the error. My question here is actually for any kind of guidance in finding the problem which is probably outside the posted code. – Museful Jun 14 '20 at 01:27
  • @PaulSanders See [here](http://cpp.sh/5rroc) for a compilable code example (in which the error also disappears). – Museful Jun 14 '20 at 01:29
  • 1
    The only guidance I can suggest is attempting to decipher all the diagnostics that gcc spews out, when reporting the error. Sometimes one is capable of figuring out the problem, after pouring over a typical hairball of errors, one by one, until you get to the truth. It's an acquired skill, I must admit it, but one has to have full access to the entire source code, in order to be able to chase every referenced file+line number to its source, put it together with what the error message says, then go to the next one, keeping everything in mind, until a complete picture emerges. – Sam Varshavchik Jun 14 '20 at 01:29
  • You could start with the whole code and remove parts until the error disappears. Put that part back and remove other parts of the code. Currently there is much code that doesn't cause the problem. – Thomas Sablik Jun 14 '20 at 01:31
  • @SamVarshavchik I get from GCC exactly the message listed in the question, and it refers only to code also in the question. Is there a way to get GCC to report more detailed diagnostics? – Museful Jun 14 '20 at 01:33
  • 1
    Take a gander at this? https://stackoverflow.com/questions/30953248/why-doesnt-sfinae-enable-if-work-for-member-functions-of-a-class-template – Taekahn Jun 14 '20 at 01:35
  • 1
    @Taekahn I think you're right. This gets me every time. – Museful Jun 14 '20 at 01:42

0 Answers0