c++ - Explicitly delete never-use copy constructor give compile error -


i implementing sizetag method take size value , keep l-value reference.

things work fine , in code intent use t&& constructor.

however, if explicitly delete copy constructor compiler give error:

#include <cstdint> #include <type_traits> #include <utility>  template <typename t = std::uint64_t> class sizetag {   public:      using size_type = std::uint64_t;     using type = std::conditional_t<std::is_lvalue_reference<t>::value, const size_type&, size_type>;     inline const type& get() const { return _size; }      sizetag(t&& sz) : _size(std::forward<t>(sz)) { }     sizetag& operator = (const sizetag&) = delete;      sizetag(const sizetag&) = delete;   // no error if line removed    private:     type _size; };  template <typename t> sizetag<t> make_size_tag(t&& t) {   return std::forward<t>(t); }  int main() {     int = 9;     make_size_tag(a); } 

why happening? copy constructor should never called in case.

the function make_size_tag returns sizetag<t> value.

let's recap how function returning value works:

  • there temporary object called return value object.
  • for case return expression;:
    • the expression copy-initializes return value object.
    • this copy elision context.
  • for case return { zero_or_more_items };:
    • the braced list copy-list-initializes return value object.
  • if calling code initializes variable function call, return value object initializer. (the exact form of initialization may vary depending on calling code). initialization of object, copy elision context.

in code, make_size_tag(a) deduces t (the parameter of make_size_tag ) int&, because perfect forwarding scenario.

the instantiation of make_size_tag t looks like, after expanding out std::forward:

sizetag<int&> make_size_tag(int& t) {     return t; } 

because static_cast<int&>(t) same t , since t lvalue of type int.


as mentioned earlier, code copy-initializes return value object. code behaves sort of like:

sizetag<int&> temp_rv = t; 

and because t not sizetag, definition of copy-initialization same as:

sizetag<int&> temp_rv = sizetag<int&>(t); 

which invokes copy/move operation initialize temp_rv temporary of type sizetag<int&>. although copy elided copy elision, accessible copy/move constructor must exist.


the solution suggested jarod42, putting braces around return expression, works because equivalent initialization copy-list-initialization:

sizetag<int&> temp_list_rv { t }; 

which initializes temp_list_rv using sizetag<int&>(int&) constructor.


nb; code has separate bug: since type const uint64_t &, initialization of _size int creates temporary destroyed when sizetag constructor completes; , tag returns dangling reference. clang warns this, g++ doesn't.

to fix this: either need change type same t& binds directly a, e.g.:

using size_type = typename std::remove_reference<t>::type; 

or make _size not reference. seems latter defeat whole purpose of tag, might need rethink design bit.

to avoid possibility of generating danging reference, change const size_type & size_type & in conditional_t. compiler (assuming you're not using msvc) point out problem.


Popular posts from this blog

php - How should I create my API for mobile applications (Needs Authentication) -

5 Reasons to Blog Anonymously (and 5 Reasons Not To)

Google AdWords and AdSense - A Dynamic Small Business Marketing Duo