In response to your "pam.pam" compiler creates a temporary object of type std::string . Lvalue links can be bound to temporary objects only if these links are const . It always has been.
const std::string &s1 = "pam.pam"; // <- Все в порядке std::string &s2 = "pam.pam"; // <- А так нельзя
The question here is, why did you suddenly need to remove this const . If you want to modify s inside your function and at the same time consider that it “goes without saying” that the value of the argument passed by the user will be modified / damaged / destroyed, you can provide overloads
vector<std::string> split(std::string &s, char delim) { ... } vector<std::string> split(std::string &&s, char delim) { return split(s, delim); }
If you want the argument value not to be destroyed and at the same time there is no copying cost when it is not needed, then the easiest way to do it
vector<std::string> split(std::string s, char delim) { ... }
Both options allow you to do
split("pam.pam", '.');