0

Does anyone know why Dict class is invalid but Dict2 is fine?


#include <string>
#include <unordered_map>
#include <map>
#include <variant>

class Dict
{
public:
    Dict() {}

private:
    std::unordered_map<std::string, std::variant<Dict, std::string>> data;
};

class Dict2
{
public:
    Dict2() {}

private:
    std::map<std::string, std::variant<Dict2, std::string>> data;
};

int main()
{
    Dict d;
    Dict2 d2;
    return 0;
}

I get an error of

‘value’ is not a member of ‘std::is_trivially_move_constructible<Dict>’.

I looked up the concept of trivially move and copy constructible, as I understood, the move contructor should be defined or deleted. I am guessing it is because of using std::unordered_map with std::variant and the the compiler doesn't know how an object should be moved. But I am not sure if I have understood it correctly.

cigien
  • 57,834
  • 11
  • 73
  • 112
Keivan
  • 673
  • 7
  • 15

1 Answers1

1

I believe the behavior is undefined in both cases. Dict2 just happens to compile by accident of implementation; "seems to work" is one possible manifestation of undefined behavior.

[res.on.functions]/1 In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ standard library depends on components supplied by a C++ program. If these components do not meet their requirements, this International Standard places no requirements on the implementation.

[res.on.functions]/2 In particular, the effects are undefined in the following cases:
...
(2.5) — if an incomplete type (6.9) is used as a template argument when instantiating a template component, unless specifically allowed for that component.

Dict and Dict2 are incomplete types until the closing brace of their definitions. std::variant doesn't specifically allow being instantiated with an incomplete type.

Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85
  • Thanks for the answer. So how to suggest to solve the issue? I also tested further with `std::map` and it behaves the way I expect it. I can create a `key1` that points to a `std::string` and also a `key2` that points to an object of the same class mimicking linked lists behavior. But I cannot do this with `std::unordered_map` simply because it doesn't compile. – Keivan Dec 07 '20 at 09:46
  • 1
    Well, as a quick workaround, you could allocate the nested `Dict` on the heap, as in `std::variant, std::string>`. `std::unique_ptr` explicitly allows incomplete type as a parameter. – Igor Tandetnik Dec 07 '20 at 13:30