8

Consider following code:

template <typename T> struct X
{
    X(T) {}
    void foo() {}
};

template <typename T> struct Y
{
    int object = 0;

    void bar()
    {
        X(object).foo();
    }
};

Live on gcc.godbold.org

GCC 8.2 compiles it, while Clang 7 spits out following error:

<source>:13:18: error: member reference base type 'X' is not a structure or union
        X(object).foo();
        ~~~~~~~~~^~~~

This looks like a bug to me.

The conditions are very specific: If either structure is not a template, or if object is not a member variable, or if CTAD (class template argument deduction) is not involved, then Clang compiles the code as well.

What's going on here? Is it indeed a Clang bug?

And what's more important, how can I make the code compile with minimal changes, preferrably without getting rid of CTAD?


The only flag used is -std=c++17.

clang++ --version is

clang version 7.0.0 (tags/RELEASE_700/final 342594)
Target: x86_64-unknown-linux-gnu
Thread model: posix
Maximillian Laumeister
  • 19,884
  • 8
  • 59
  • 78
HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • Or maybe not, but this error occurs when you're referencing a type that the compiler cannot deduce. maybe `X(object)` would fix it. – Jazzwave06 Dec 04 '18 at 18:13
  • Also `auto a = X(object); a.foo();` fixes it. – Jazzwave06 Dec 04 '18 at 18:16
  • @sturcotte06 If that works his code should work as well. – David G Dec 04 '18 at 18:17
  • @sturcotte06 Adding `` fixes it (as the question mentions), but I want to use CTAD, since my actual code is more complicated. Making a temporary variable seems like a good workaround, and this is what I'm doing while waiting for a better solution or a Clang bugfix. – HolyBlackCat Dec 04 '18 at 18:18
  • 1
    I think the best workaround until clang gets fixed is to go old-school and use a function for the template deduction: https://gcc.godbolt.org/z/M3HxCN –  Dec 04 '18 at 18:19

1 Answers1

9

Yes, this is clang bug see Class template argument deduction with deduced type fails when accessing member which says:

Try to compile the following c++ program:

  template <class T>
  struct C {
    C(T) {}
    int a;
  };

  template <class T>
  int foo(T v) {
    return C{v}.a; // <----
  }

  int main() {
    foo(4);
  }

The line marked above fails with the error:

error: member reference base type 'C' is not a structure or union
    return (C{v}).a;
           ~~~~~~^~

The bug report also specifies cases that do work, which may or may not be alternatives.

Note that the following all work fine:

  template <class T>
  C<T> foo(T v) {
    return C{v};
  }

and

int foo(int v) {
    return C{v}.a;
  }

and

  C{4}.a;

I tried this also on a recent trunk build (trunk 346600)

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740