Insert/find issues in Binary Tree - c++

UPDATE: This issue only appears when I use the binary tree for strings. If I feel it with ints, everything works fine!
A few months ago I wrote a Binary Tree implementation in C++. Everything seemed to work okay (insert, remove, traversals, find...) and I passed my exams :) But now when I write a new class based on this binary tree class, the find method seems to be buggy, but I can't find the reason.
Here is the issue: find returns a pointer to a node, but for some reason I can access its member variables only when this node is the root. I can't quite understand why. Something to do with poiters? Or is there something wrong in my insert function? Can someone help me, because I feel a bit lost :)
Here is my Binary Tree interface:
template <class N>
class Node {
public:
N data;
Node* left;
Node* right;
Node* parent;
};
template <class B>
class BinaryTree {
protected:
Node<B>* m_root;
unsigned int m_height; // longest path in tree
unsigned int m_size; // total number of nodes
// methods that support public methods of below
void __insert(Node<B>* element, B value);
void __inorder(Node<B>* element);
void __preorder(Node<B>* element);
void __postorder(Node<B>* element);
void __remove(Node<B>* element, B value);
void __update_parent(Node<B> *element);
void __destroy_tree(Node<B>* element);
int __get_height(Node<B>* element);
Node<B>* __find(Node<B>* element, B value);
Node<B>* __find_minimal(Node<B> *element);
public:
BinaryTree(); // Default constructor
~BinaryTree(); // Default deconstructor
void insert(B value);
void inorder();
void preorder();
void postorder();
void remove(B value);
int get_size();
int get_height();
bool is_empty();
bool find(B value);
bool check_find(B value);
};
Insert:
template <class B>
void BinaryTree<B>::insert(B value) { // Creates a new node in the tree with value
if(m_root == NULL) {
m_root = new Node<B>; // creating the root if it's empty
m_root->data = value;
m_root->left = NULL;
m_root->right = NULL;
m_root->parent = NULL;
}
else {
Node<B>* element = m_root;
__insert(element, value);
}
}
template <class B>
void BinaryTree<B>::__insert(Node<B>* element, B value) {
if(value < element->data) {
if(element->left != NULL)
__insert(element->left, value);
else {
element = element->left;
element = new Node<B>;
element->data = value;
element->left = NULL;
element->right = NULL;
element->parent = element;
m_size++;
}
}
else if(value >= element->data) {
if(element->right != NULL)
__insert(element->right, value);
else {
element = element->right;
element = new Node<B>;
element->data = value;
element->left = NULL;
element->right = NULL;
element->parent = element;
m_size++;
}
}
}
Find:
template <class B>
Node<B>* BinaryTree<B>::__find(Node<B>* element, B value) {
if(element != NULL) {
if(value == element->data)
return element;
else if(value < element->data)
__find(element->left, value);
else if(value > element->data)
__find(element->right, value);
}
else
return NULL;
}
Finally, a function that tests find. Even if the values match, it returns only True when the found node is m_root. Why?
template <class B>
bool BinaryTree<B>::check_find(B value) {
Node<B>* node = __find(m_root, value);
if(node != NULL && node->data == value)
return true;
return false;
}
Why?
More links:
Full code of my Binary Tree implementation:
https://github.com/vgratian/CS-121-Data-Structures/tree/master/graphs
Program where I use this Binary Tree:
https://github.com/vgratian/rate-ur-prof

The problem lies with your find implementation:
else if(value < element->data)
__find(element->left, value);
else if(value > element->data)
__find(element->right, value);
This only works for types/classes for which the relational operators < and > are defined (in a relevant way). So it will not work whe B is an std::string for example.
For string matching, consider using a Trie.

in your insert function, you don't actually insert the element into the tree.
you create a new node, and set it's parent to point to itself. also, you didn't updated the parent left/right pointers to the new node.
take a look in the added comments:
if(element->left != NULL)
__insert(element->left, value);
else { // meaning element->left == NULL
element = element->left; // element = NULL
element = new Node<B>; // element = new node
element->data = value;
element->left = NULL;
element->right = NULL;
element->parent = element; // element->parent = new node.element parent point to himself

Related

How to call a function method recursively in classes in c++?

So, I started learning and reading about OOP not so long ago, I've been implementing all the data structures I know using classes and objects just for overall practice and to get comfortable with using OOP in c++.
I'm implementing the tree data structure and I've been wondering how to call a method recursively(I'm aware that I have to pass in an argument) so that when I create an object in main and call a specific method it's written like the following a.inorder(); and not a.inorder(root) since root is a private attribute.
Is this possible ?
My code:
#include<iostream>
using namespace std;
struct node
{
int data;
node* left;
node* right;
};
class tree
{
private:
node* root;
public:
tree();
tree(int val);
void insert(int val);
void preorder();
void postorder();
void inorder();
int count();
};
tree::tree() : root { NULL }
{
}
tree::tree(int val)
{
root = new node;
root->data = val;
root->left = root->right = NULL;
}
void tree::insert(int val)
{
if (!root)
{
root = new node;
root->data = val;
root->left = root->right = NULL;
}
else
{
node* t = root;
node* p = NULL;
while (t)
{
p = t;
if (val > root->data)
t = root->right;
else
t = root->left;
}
t = new node;
t->data = val;
t->left = t->right = NULL;
if (p->data > t->data)
p->left = t;
else
p->right = t;
}
}
void tree::preorder()
{
if (root)
{
}
}
In your design, a node refers to itself. Since it is the node object that is recursive, you could define the recursive method on node:
struct node
{
int data;
node* left;
node* right;
void preorder() {
//...
left->preorder();
right->preorder();
}
};
And then, tree::preorder() would just dispatch a call to root->preorder().
Write a private static recursive function passing to it the pointer to the root node and call the function from the corresponding public non-static member function.
For example
public:
std::ostream & preorder( std::ostream &os = std::cout ) const
{
return preorder( root, os );
}
//...
private:
static std::ostream & preorder( const node *root, std::ostream &os );
//...
This is a comment rather than an actual answer, as it addresses a different issue than you are asking about. However, it is too long for a comment space, that's why I post it here.
I suppose you erroneously refer to root in this part
while (t)
{
p = t;
if (val > root->data)
t = root->right;
else
t = root->left;
}
IMHO it should look like this:
while (t)
{
p = t;
if (val > t->data)
t = t->right;
else
t = t->left;
}
Also compare the code to seek a place for insert with a code that makes an actual insertion:
if (p->data > t->data)
p->left = t;
else
p->right = t;
You've put a comparison subexpressions in reversed order - when seeking, you test whether the new value is greater than that in an existing node, but when inserting, you test whether the existing value is greater than the new one. If they differ, the code will work OK, because you also swapped left and right in the 'then' and 'else' branch.
However, if the values appear equal, the execution control will go to 'else' in both places. As a result the testing code may stop at empty left pointer, but then a new node would get appended to the right, which was not tested for being NULL.
Why would the tree class do intrinsic operations on node? The node class knows best the node's internal structure, so let it initialize itself. This will also help you to stick to the DRY principle and, indirectly, to the KISS principle, as well as the Single-responsibility principle.
struct node
{
int data;
node* left;
node* right;
node(int val) : data(val), left(NULL), right(NULL) {}
};
class tree
{
private:
node* root;
public:
tree();
tree(int val);
void insert(int val);
};
tree::tree() : root { NULL }
{
}
tree::tree(int val) : root(new node(val))
{
}
void tree::insert(int val)
{
if (!root)
{
root = new node(val);
}
else
{
node* t = root;
node* p = NULL;
while (t)
{
p = t;
if (val < t->data)
t = t->left;
else
t = t->right;
}
t = new node(val);
if (t->data < p->data)
p->left = t;
else
p->right = t;
}
}
Additionally, you can make insert recursive, too.
struct node
{
int data;
node* left;
node* right;
node(int val) : data(val), left(NULL), right(NULL) {}
};
class tree
{
private:
node* root;
public:
tree();
tree(int val);
void insert(int val);
protected:
void insertat(node* p, int val);
};
void tree::insert(int val)
{
if (!root)
root = new node(val);
else
insertat(root, val);
}
void tree::insertat(node* t, int val);
{
if (val < t->data)
{
if (t->left)
insertat(t->left, val);
else
t->left = new node(val);
}
else
{
if (t->right)
insertat(t->right, val);
else
t->right = new node(val);
}
}

Errors defining templated class functions

I'm working on a template assignment for class and my code is giving me errors at these specific lines. "'T' is not a valid template type argument for parameter 'T'"
It's real confusing for me because I've never worked with namespaces before. Nor have I worked with an .inl. Could someone help correct my code? I've inserted comments at where the compiler is giving me errors, they're the functions that return a Node*. My code is not finished either.
BST.hpp
#ifndef BST_HPP
#define BST_HPP
namespace Tree{
template<class T>
class BST {
public:
BST();//default constructor
BST(T rootkey);//constructor with 1 parameter for root key
~BST();//destructor
void insert(T value); //function named insert with 1 parameter(key value to insert)
Node* remove(class Node* troot,T value);//function named remove with 1 parameter (key value to remove)
Node* min(class Node* mini);
private:
class Node {
public:
Node();//default constructor
Node(T k);//constructor with 1 parameter (key value)
~Node(); //destructor
Node* getP(); //parent accessor
Node* getL();//left accessor
Node* getR();//right accessor
parent mutator
left mutator
right mutator
operator <
operator ==
operator !=
operator <<
private:
T key;
Node *parent;
Node *left;
Node *right;
};
Node *root;
void destroy(Node* r);
};
};
#include "BST.inl"
#endif
BST.inl
#include "BST.hpp"
template<class T>
inline Tree::BST<T>::BST(T rootkey)
{
root = new Node(rootkey);
root->setP(0);
}
template<class T>
inline Tree::BST<T>::BST()
{
root = new Node();
}
template<class T>
inline Tree::BST<T>::~BST()
{
delete root;
}
template<class T>
inline void Tree::BST<T>::insert(T value)
{
Node *temp = root;
Node *prev;
do
{
if (value < temp->getK())
{
prev = temp;
temp = temp->getL();
}
else if (value >= temp->getK())
{
prev = temp;
temp = temp->getR();
}
} while (temp != NULL);
temp = new Node(value);
temp->setP(prev);
if (temp->getK() > prev->getK())
{
prev->setR(temp);
}
else
{
prev->setL(temp);
}
}
template<class T>
inline Node * Tree::BST<T>::remove(Node *troot, T value)//ERROR
{
Node *temp;
if (troot == NULL)
{
return troot;
}
else if (value > troot->getK())
{
return remove(troot->getR(), value)
}
else if (value < troot->getK())
{
return remove(troot->getL(), value)
}
else
{
if (troot->getL() == NULL && troot->getR() == NULL)
{
delete troot;
troot = NULL;
return troot;
}
else if (troot->getR() == NULL)
{
temp = troot;
troot = troot->getL();
return troot;
}
else if (troot->getL() == NULL)
{
temp = troot;
troot = troot->getR();
return troot;
}
else
{
temp = min(troot->getR());
troot->setK(temp->getK());
troot->getR() = remove(troot->getR, temp->getK());
}
}
return troot;
}
template<class T>
inline Node * Tree::BST<T>::min(Node * mini)//ERROR
{
if (mini->getL() != NULL)
{
mini = mini->getL();
}
else
return mini;
}
template<class T>
inline Tree::BST<T>::Node::Node()
{
key = 0;
}
template<class T>
inline Tree::BST<T>::Node::Node(T k)
{
key = k;
}
template<class T>
inline Tree::BST<T>::Node::~Node()
{
delete getL();
delete getR();
}
template<class T>
inline Node * Tree::BST<T>::Node::getP()//ERROR
{
return parent;
}
template<class T>
inline Node * Tree::BST<T>::Node::getL()//ERROR
{
return left;
}
In this line:
template<class T>
inline Node * Tree::BST<T>::Node::getP() {
There is no Node class at global scope for you to return. That's the only thing Node can refer to so far, since the compiler is still not inside BST<T>'s scope to find the internal Node. There are two ways to fix this:
Fully qualify the Node (works since C++98):
template<class T>
inline Tree::BST<T>::Node * Tree::BST<T>::Node::getP() {
This fully qualifies the scope where Node is.
Use a trailing return type (my personal preference, C++11 and onward):
template<class T>
inline auto Tree::BST<T>::Node::getP() -> Node* {
This delays the lookup of Node until it may begin inside the scope of the class.

Binary Tree Destructor Issue

I have recently been implementing a binary tree in my free-time and I do believe I have it working correctly. However, I have ran into a mysterious segmentation fault when running a simple test. Here is my implementation of the binary search tree:
//the binary search tree class
template <class M>
class BS_Tree {
private:
//node structure
struct Node {
M data; //the key of the node
Node* left,* right,* parent; //node pointers to left right and parent
Node(M key, Node* p) //parameterized node constructor
: data(key), left(nullptr), right(nullptr), parent(p) {}
};
Node* root; //the root node of the binary search tree
bool is_left(Node* n) {return n->parent->left == n;} //utility function
void destroy(Node* n); //used for tree destruction
void duplicate(Node* const &, Node* &); //used for copy construction
public:
BS_Tree() {root = nullptr;} //constructor
~BS_Tree() {destroy(root);} //destructor
BS_Tree(const BS_Tree &); //copy constructor
BS_Tree &operator=(const BS_Tree &); //copy assignment operator
Node* find(M key); //find function
void insert(M); //insert function
void erase(Node*); //erase function
Node* get_root() {return root;}
};
//destroy function used for tree destruction
template <class M>
void BS_Tree<M>::destroy(Node* n) {
if(n) { //recursively erase the tree
if(n->left) destroy(n->left);
if(n->right) destroy(n->right);
delete n;
}
}
//duplicate function used for copy construction
template <class M>
void BS_Tree<M>::duplicate(Node* const &one, Node* &two) {
if(!one) two = nullptr;
else { //recursively duplicate the tree
two = new Node(one->data);
duplicate(one->left, two->left);
duplicate(one->right, two->right);
}
}
//copy constructor
template <class M>
BS_Tree<M>::BS_Tree(const BS_Tree &b) {
if(!b.root) root = nullptr; //update root
else duplicate(b.root, this->root); //call duplicate function
}
//copy assignment operator
template <class M>
BS_Tree<M> &BS_Tree<M>::operator=(const BS_Tree &b) {
if(!b.root) root = nullptr; //update root
else { //destroy current tree and duplicate source tree
this->~BS_Tree();
duplicate(b.root, this->root);
}
}
//function to find a key and return a pointer
template <class M>
typename BS_Tree<M>::Node* BS_Tree<M>::find(M key) {
Node* i = root; //create an index
while(i) {
//try to find the key
if (i->data == key) return i;
if(i->data > key) i = i->left;
else i = i->right;
}
//return a pointer to the key, nullptr if not found
return i;
}
//function to insert a new node
template <class M>
void BS_Tree<M>::insert(M key) {
if(!root) { //if no tree, make new node the root
root = new Node(key, nullptr);
return;
}
Node* i = root; //create an index
while(true) { //find insertion point and insert new node
if(i->data > key) {
if(!i->left) {
i->left = new Node(key, i);
return;
}
else i = i->left;
}
if(i->data <= key) {
if(!i->right) {
i->right = new Node(key, i);
return;
}
else i = i->right;
}
}
}
//Function to erase a node
template <class M>
void BS_Tree<M>::erase(Node* n) {
if(n) {
//no children case
if(!n->left && !n->right) {
if(root == n) root = nullptr; //if node is root, make root null
else { //if node is a child, update parent's children
if(is_left(n)) n->parent->left = nullptr;
else n->parent->right = nullptr;
}
delete n; //erase the node
return;
}
//one child cases
if(!n->left) {
if(n == root){ //if node is root, update root
root = n->right;
n->right->parent = nullptr;
} else { //if node is a child, update parent's children and nodes parent
if(is_left(n)) n->parent->left = n->right;
else n->parent->right = n->right;
n->right->parent = n->parent;
}
delete n; //erase the node
return;
}
if(!n->right) {
if(n == root){ //if node is root, update root
root = n->left;
n->left->parent = nullptr;
} else { //if node is a child, update parent's children and nodes parent
if(is_left(n)) n->parent->left = n->left;
else n->parent->right = n->left;
n->left->parent = n->parent;
}
delete n; //erase the node
return;
}
//two children case
else {
Node* i = n; //create an index
i = i->right; //find successor
while(i->left) i = i->left;
n->data = i->data; //set nodes data to successor's data
if(is_left(i)) i->parent->left = i->right; //update successor's parent and its child
else i->parent->right = i->right;
if(i->right) i->right->parent = i->parent;
delete i; //erase successor node
return;
}
}
}
As for the test, it is a simple linear vector element insert vs time performance check. It takes a max number of elements and an increment of elements for each test. It then runs the test for each increment and times the insertions. It works fine for the first few iterations (i.e n = 10000, 20000, 30000, 40000), but then I reach a segmentation fault after insertion when the 50000 element tree destructor is called. It is hinting at the line:
if(n->right) destroy(n->right);
I understand that I am doing an incremental insertion so all of my elements are on the right side of the tree, but I am having a hard time figuring out where I went wrong and why it only messes up on this iteration.
My test implematation:
int main(){
//number of elements, max test elements, and test increment
int n, t = 100000, i = 10000;
//run the test a number of times
for(n = i; n <= t; n += i) {
//get an incremental vector of size n
std::vector<int> test(n);
std::iota(std::begin(test), std::end(test), 0);
//run the insert test print the time interval
BS_Tree<int> m;
auto ibs_start = clock();
for(auto i : test){
m.insert(i);
}
auto ibs_stop = clock();
std::cout << n << ' ' << (ibs_stop - ibs_start)/double(CLOCKS_PER_SEC)*1000 << "\n";
}
return 0;
}
If someone could help I would greatly appreciate it!
Edit: Could it simply be my stack overflowing due to the destroy function having to store all of the elements before reaching the bottom and actually deleting anything?
If it works for some number of items (40000), but not for a larger, it might be a stackoverflow. Looking at the code also confirms this: destroying is recursive, and in the case of extremely unbalanced tree, it means as many stack frames as many nodes.
The question is how this could be solved without recursion? This is not so obvious, as there are two recursive calls. My solution is to traverse the binary tree, post-order, and delete leaf nodes.
Here is a solution -- an iterative version of the destroy method:
//destroy function used for tree destruction
template <class M>
void BS_Tree<M>::destroy(Node* n) {
if (n) { // iteratively erase the tree
Node* c = n; // current node
while (true) {
if (c->right) {
// it has right child, descend to it
c = c->right;
continue;
}
if (c->left) {
// it has left child, descend to it
c = c->left;
continue;
}
// this node has no (more) children, destroy it
Node* p = c->parent;
if (p) {
// update its parent to no longer point to it
if (p->right == c) p->right = NULL; // we came from left
else if (p->left == c) p->left = NULL; // we came from left
}
// destroy the node
delete c;
// go back to its parent
c = p;
if (c == n) {
// where at back at start node, stop
delete n;
break;
}
}
}
}
Update: I have tested my solution, and made some small changes.

insert method of C++ template class

Below is what I have implemented so far. When debugging the following code after I execute
"n = new node(val, NULL, NULL);" in the insert method and leave the insert method, the "val" is NOT saved in the root node once I leave the method and I do not understand why.
// Creates an empty binary tree
template<class T> binTree<T>::binTree() {
root = NULL;
}
template<class T> void binTree<T>::insert(T val) {
insert(val, root);
}
template<class T> void binTree<T>::insert(T val, node* n) {
if (n == NULL) {
n = new node(val, NULL, NULL); // <=============Not actually storing the value into the node after this method is done
} else if (val < n->val) {
if (n->left == NULL) {
n->left = new node(val, NULL, NULL);
} else {
insert(val, n->left);
}
} else if (val > n->val) {
if (n->right == NULL) {
n->right = new node(val, NULL, NULL);
} else {
insert(val, n->right);
}
}
}
and here is my private struct in the header file:
private:
struct node {
T val;
node* left;
node* right;
node(T v, node* l, node* r) :
val(v), left(l), right(r) {
}
};
void destruct(node* n);
void insert(T val, node* n);
T find(T val, node* n) const;
T remove(T val, node* n, node* parent);
node* root;
};
You are accepting the pointer by value, so you are only modifying the local variable n, changes to which are lost when the function returns.
Maybe you meant to take n by reference, like node*& n? This means that changes to n inside the function will affect the parameter you pass into the function.

C++ custom template LinkedList crashes adding std::string

For academic purposes, I'm trying to develop a little "textual adventure game". I have to implement all data structures by my own. Now, I have some problems with the implementation of a generic (template) LinkedList.
In the specific, this data structure works with everything (primitive data types and custom objects) BUT strings! (standard library strings).
When I try to add strings to a list, the application crashes with the following error (in console):
"terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_constructor null not valid"
The list is implemented as a "double linked list" using the head-node as first-last node
Here the code ("Abstract" List interface):
#ifndef LIST_H_
#define LIST_H_
template <class T>
class List
{
public:
virtual ~List() {}
virtual T get(int position) = 0;
virtual List* add(T item) = 0;
virtual List* insert(T item, int position) = 0;
virtual List* remove(int position) = 0;
virtual int size() const = 0;
virtual bool isEmpty() const = 0;
protected:
private:
};
#endif /* LIST_H_ */
This is the LinkedList implementation (the "node" class):
#include "List.h"
#include <stdlib.h>
#ifndef LINKEDLIST_H_
#define LINKEDLIST_H_
template <class T>
class ListNode
{
public:
ListNode(T item)
{
mItem = item;
mNext = NULL;
mPrev = NULL;
}
ListNode(T item, ListNode<T>* next, ListNode<T>* prev)
{
mItem = item;
mNext = next;
mPrev = prev;
}
~ListNode()
{
delete &mItem;
}
T getItem()
{
return mItem;
}
ListNode<T>* getNext()
{
return mNext;
}
ListNode<T>* getPrev()
{
return mPrev;
}
void setItem(T item)
{
mItem = item;
}
void setNext(ListNode<T>* next)
{
mNext = next;
}
void setPrev(ListNode<T>* prev)
{
mPrev = prev;
}
protected:
private:
T mItem;
ListNode<T> *mNext, *mPrev;
};
The LinkedList class:
template <class K>
class LinkedList : public List<K>
{
public:
LinkedList()
{
mSize = 0;
mFirstNode = NULL;
}
~LinkedList()
{
// implementazione distruttore tramite ciclo sui nodi
}
K get(int position)
{
K item = NULL;
ListNode<K>* targetNode = getNodeAtPosition(position);
if (targetNode != NULL) item = targetNode->getItem();
return item;
}
List<K>* add(K item)
{
if (mFirstNode == NULL)
{
mFirstNode = new ListNode<K>(item);
mFirstNode->setNext(mFirstNode);
mFirstNode->setPrev(mFirstNode);
}
else
{
ListNode<K>* newNode = new ListNode<K>(item, mFirstNode, mFirstNode->getPrev());
mFirstNode->getPrev()->setNext(newNode);
mFirstNode->setPrev(newNode);
}
mSize++;
return this;
}
List<K>* insert(K item, int position)
{
ListNode<K>* targetNode = getNodeAtPosition(position);
if (targetNode != NULL)
{
ListNode<K>* newNode = new ListNode<K>(targetNode->getItem(), targetNode->getNext(), targetNode);
targetNode->setItem(item);
targetNode->setNext(newNode);
mSize++;
}
return this;
}
List<K>* remove(int position)
{
ListNode<K>* targetNode = getNodeAtPosition(position);
if (targetNode != NULL)
{
targetNode->setItem(targetNode->getNext()->getItem());
targetNode->setNext(targetNode->getNext()->getNext());
//delete targetNode->getNext();
mSize--;
}
return this;
}
int size() const
{
return mSize;
}
bool isEmpty() const
{
return (mFirstNode == NULL) ? true : false;
}
protected:
ListNode<K>* getNodeAtPosition(int position)
{
ListNode<K>* current = NULL;
if (mFirstNode != NULL && position < mSize)
{
current = mFirstNode;
for (int i = 0; i < position; i++)
{
current = current->getNext();
}
}
return current;
}
private:
int mSize;
ListNode<K>* mFirstNode;
};
#endif /* LINKEDLIST_H_ */
Suggestions?
Part of your problem is here:
ListNode(T item)
{
mItem = item; // for a std::string, this will be a class member, non-pointer
mNext = NULL;
mPrev = NULL;
}
ListNode(T item, ListNode<T>* next, ListNode<T>* prev)
{
mItem = item; // same here
mNext = next;
mPrev = prev;
}
~ListNode()
{
delete &mItem; // you are attempting to delete an item you never created
}
You should either change your constructors to create a T* object on the heap (which will then be deleted in your destructor), or remove the delete line from your destructor.
This problem will be evident with far more than just std::string, by the way.
Somewhere in your program you are doing this:
std::string s(nullptr);
Calling std::string's constructor with a null pointer is causing it to throw a std::logic_error exception.
From the standard:
ยง 21.4.2
basic_string(const charT* s, size_type n, const Allocator& a = Allocator());
Requires: s shall not be a null pointer and n < npos.
It seems it's not possible to pass std::string as template argument...
Strings as Template Arguments
Now I use an "old" - char const* - to achieve the expected result, even if I have to implement my personal "utils" methods to work with those pointers now...