Is a function type dependent if it depends only on its own template parameters?

I came across inconsistency in how the current C ++ compilers (clang / gcc) determine if the name depends. The following example A::fdepends, but ::fnot, which leads to an error when using the latter.

template<typename>
struct B
{
    typedef int Type;
};

template<typename U>
static U f(U u);

template<typename T>
struct A
{
    template<typename U>
    static U f(U u);

    typename B<decltype(f(0))>::Type m1; // typename required
    B<decltype(::f(0))>::Type m2; // typename not required
};

The inconsistent part is that the declaration A::fdoes not depend on the template parameter A, which means there is no need to consider it as a dependent name.

This behavior is apparently covered by the following wording in the C ++ 11 standard:

[temp.dep.expr] / 3

Id is type dependent if it contains

  • identifier associated with a search by name with one or more ads declared with a dependent type

[temp.dep.type] / 3

,

  • ,

::f , . A::f -?

+4
1

, f .

14.6.2.2 [temp.dep.expr]

3 id ,

  • , , ,

, -: . U , , f<int> U(U) int(int). , , -, , , , .

  • , ,
  • , ,

. < >, , .

  • , ;

. .

, " T" T (14.5.1.3).

: .

, , f . :

14.6.2.1 [temp.dep.type]

5 ,

  • , [...].
  • , [...].
  • , (5.2.5), [...].

: f , .

f , , f .

, , , , . , , ++. , , , :

#include <cstdio>

void f(const char *s, ...) { std::printf("%s: non-dependent\n", s); }

struct S1 { };

template <typename T>
struct S2 {
  static S1 a;
  static S1 b() { return {}; }
  template <typename U>
  static U c() { return {}; }
  static void z() {
    f("S1()", S1()); // sanity check: clearly non-dependent
    f("T()", T()); // sanity check: clearly dependent
    f("a", a); // compiler agreement: non-dependent
    f("b()", b()); // compiler disagreement: dependent according to GCC 4.8, non-dependent according to clang
    f("c<T>()", c<T>()); // sanity check: clearly dependent
    f("c<S1>()", c<S1>()); // compiler agreement: dependent
    f("decltype(b())()", decltype(b())()); // compiler agreement: dependent
  }
};

void f(const char *s, S1) { std::printf("%s: dependent\n", s); }

// Just to show it possible to specialize the members
// without specializing the full template.
template <>
S1 S2<S1>::b() { return {}; }
template <>
template <>
S1 S2<S1>::c<S1>() { return {}; }

int main() {
  S2<S1>::z();
}

clang b(), decltype(b())() c<S1>() . . . , -, , S2<S1>::b S2<S1>::c<S1>, .

+3

Source: https://habr.com/ru/post/1569092/


All Articles