dimanche 27 novembre 2016

gcc: “inline function used but never defined” in connection with ADL and template trickery

I was playing around with constexpr counters in C++ (based on this), but there's a warning emitted by GCC that I can't get rid of. Below is a fairly minimal source demonstrating the problem. Clang emits no warning, GCC emits two (see below), one I can get rid of easily, but I didn't clutter the code with the workaround, the other baffles me. Both programs behave the same, correctly, as far as I understand.

All of the search results for the error message deal with people not doing inline functions right and other non-related issues. I've searched. I've tried pragmas, but since gcc doesn't seem to connect the warning to a warning option (e.g. -Wnon-template-friend), I can't even do that.

How can I get rid of that warning?

The warning I know how to get rid of, in multiple ways even.

question.cpp:4:32: warning: friend declaration ‘constexpr int fn(tag)’ declares a non-template function [-Wnon-template-friend]
  friend constexpr int fn(tag);
                              ^
question.cpp:4:32: note: (if this is not what you intended, make sure the function template has already been declared and add  after the function name here) 

This warnig I can't get rid of

question.cpp:4:23: warning: inline function ‘constexpr int fn(tag)’ used but never defined [enabled by default]
  friend constexpr int fn(tag);
                       ^
question.cpp:4:23: warning: inline function ‘constexpr int fn(tag)’ used but never defined [enabled by default]
question.cpp:4:23: warning: inline function ‘constexpr int fn(tag)’ used but never defined [enabled by default]
#include <stdio.h>

template <int N> struct tag {
    friend constexpr int fn(tag<N>);
};
template <int N>
struct setter {
    static constexpr int v=N;
    friend constexpr int fn(tag<N>) { return v; }
};
template <int N, int Z=fn(tag<N+0>{})>
static constexpr bool is_set(int  ,tag<N>) {
    return true;
}
template <int N>
static constexpr bool is_set(float,tag<N>) {
    return false;
}
template<int N>
static constexpr int set(int Q = setter<N+0>::v) {
    return fn(tag<N>{});
}
template<int N,bool B=is_set(1,tag<N+0>{})> 
    static constexpr bool is_set() {return B;}

int main() {
    set<1>();
    printf ("%d %d %d %d\n",is_set<0>(),is_set<1>(),is_set<2>(),is_set<3>());
}

Aucun commentaire:

Enregistrer un commentaire