0

I have defined a template class buffer and another class buffer_view with a template constructor to take any definition of class buffer. The idea is for buffer_view to act as a single type reference-ish to any buffer type.

template<size_t N> class buffer
{
private:
    friend class buffer_view;
};

class buffer_view
{
public:
    template<size_t N>
    buffer_view(const buffer<N>& bfr)
        :m_size(N) {}

    size_t size() const { return m_size; }
    
private:
    size_t m_size;
};

It seems to work as expected:

void foo(const buffer_view& bview)
{
    std::cout << bview.size() << " _ " << std::flush;
}

int main() {
    buffer<8> bfr;
    buffer_view bview(bfr);

    foo(bview);
    foo(buffer_view(bfr));
    foo(buffer_view(buffer<32>()));
}

8 _ 8 _ 32 _

However, this doesn't work:

buffer_view bview2(buffer<16>());
foo(bview2);

bview2 gets type buffer_view (buffer<16U> (*)()) or buffer_view (* )(buffer<16u> (*)())?. See error messages:

MSVC 15.1

Error (active) E0415 no suitable constructor exists to convert from "buffer_view (buffer<16U> (*)())" to "buffer_view"

gcc 5.3.0

error: invalid initialization of reference of type 'const buffer_view&' from expression of type 'buffer_view (* )(buffer<16u> (*)())'

note: in passing argument 1 of 'bool foo(const buffer_view&)'

Best I can tell the type buffer_view (* )(buffer<16u> (*)()) is a function pointer to a function that returns buffer_view and takes as argument a function pointer to a function that takes no arguments and returns buffer<16u>?

My question then is, what's going on? Why does it not work as expected when used in a named variable but it does when used in a temporary foo(buffer_view(buffer<32>()))? - the syntax seems similar to me.

Community
  • 1
  • 1
Ramon
  • 1,169
  • 11
  • 25
  • why don't you put whole class buffer_view under template? Why only constructor? – Marek Vitek Jun 21 '17 at 17:09
  • @MarekVitek I want to use `buffer_view` as a single type, so that I don't have to template functions or classes that use it. It's completely unrelated to my actual issue though (what I now know as Most vexing parse) – Ramon Jun 21 '17 at 17:14
  • It looks, that is is compiling just fine https://godbolt.org/g/C2KkEJ Any compiler options you have enabled? EDIT:I have changed wrong numbers. Now the link is correct. – Marek Vitek Jun 21 '17 at 17:15
  • Yeah that part works fine, this `buffer_view bview(buffer<16>()); foo(bview);` doesn't - unless I add another set of brackets `buffer_view bview((buffer<16>()));` – Ramon Jun 21 '17 at 17:19
  • Answer to your problem is probably here [C++ template constructor](https://stackoverflow.com/questions/3960849/c-template-constructor) – Marek Vitek Jun 21 '17 at 17:29
  • I guess, it is because first and second bview in main are of different type. Try to change those lines to this `buffer_view bview2=buffer_view(buffer<16>());` `foo(bview2);` https://godbolt.org/g/tijoww – Marek Vitek Jun 21 '17 at 17:48
  • `buffer_view` doesn't, and shouldn't, have a default constructor so that wouldn't work. The problem is that `buffer_view bview(buffer<16>())` is parsed as a function pointer, not as a `buffer_view` constructed with a temporary `buffer<16>` object - it's not a problem per se, that's how the standard defines it. See the question marked as a duplicate of, and [this](https://en.wikipedia.org/wiki/Most_vexing_parse). – Ramon Jun 21 '17 at 18:54
  • Well I finally got it. See [this code](https://godbolt.org/g/NJDG8p) Due to my habit to instantiate by assignment I have made your problem go away. And by incorrectly modifying your code I did create myself completely new problem. Rather simple bug, I would say. I definitely learned something Today. I hope I didn't made too much confusion around. – Marek Vitek Jun 21 '17 at 20:01
  • In my actual code there wasn't a name conflict, I've edited the question to show the second variable as `bview2`. What you are suggesting shouldn't work because `buffer_view` doesn't have a default constructor and the compiler can't generate one because I am defining one. So something like `buffer_view bview;` complains that there isn't a default constructor. – Ramon Jun 21 '17 at 21:57
  • What is happening in your code is interesting though, because doing something like `buffer_view bview = buffer_view(buffer<16>());` allows the compiler to only [call the constructor once and omit the copy](http://en.cppreference.com/w/cpp/language/copy_elision). So it uses the provided constructor and we get around the syntax. Nothing is really solved though as the syntax `buffer_view bview2(buffer<16>());` not working is the "problem" - not really one, as per the standard. – Ramon Jun 21 '17 at 21:57

0 Answers0