   Ambigous call "std::string" and "const std::string &"
  Hi all,After a major redesign and rework of one of my systems I've come across a bit of a problem that I'm stumped on.I have two functions in the same (template) class:IProperty* MakeProperty(const std::string &name, const std::string &initialValue){MakerType *newProp = new MakerType(mIDName, name);newProp->SetFromString(initialValue);return newProp;}IProperty* MakeProperty(const std::string &name, PropertyType value){MakerType *newProp = new MakerType(mIDName, name);newProp->Set(value);return newProp;}MakerType is a template argument that will be a class that derives from Property<template> which in turn derives from IProperty (the explanation has been simplified). SetFromString will set the property by reading in a string and converting to the correct data type and Set sets the property using its native (template) type.So as you can see the two functions above will create a new property and set its value using one of the two methods (string or native) depending on usage (both are needed for different occasions, ie, when reading and creating a property from a script file we will set by text, however when creating a property in code we would want to set it using the native data type).The problem I am having is when creating a Property<std::string> because both of these functions have the same signature (well not the same, but too similar for the compiler to choose the correct one):IProperty* MakeProperty(const std::string &name, const std::string &initialValue);IProperty* MakeProperty(const std::string &name, std::string value)Does anyone have any ideas how I can solve this problem in a generic way without adding case specific code for the string property type?Thanks, Scott   
  What do you expect to happen when someone passes "blah" as a second argument? I think the ambiguity is real, not a peculiarity of the compiler.   ;  Well that would depend upon the type of Property, I'm using a pluggable factory pattern to create my propertys (a property wraps up a data type allowing for ToString and FromString on any data type) and this code is from the PropertyMaker class.To define and include a property type in the project I wrap it up as such:class IntProperty : public Property<int>{public:IntProperty(std::string typeID, const std::string &name) : Property<int>(typeID, name){}std::string ToString(){return Utilities::ToString(mData.mValue);}void SetFromString(std::string value){Utilities::FromString<int>(mData.mValue, value);}private:static PropertyMaker<IntProperty> mRegisterThis;};Thus for each data type there is a specifically written ToString and FromString function, so if "blah" was passed as the second argument it would depend ont he property type:Property<int> or Property<bool> would attempt to convert "blah" into their respective type. The edge case it seems is Property<std::string> which should just set its value to "blah".I think I've actually fixed this by restructuring a bit, I moved to responsibility of setting the value of the property from the Maker to the factory, with no modifications to the PropertyFactory API.I'm still intrigued as to if there is another way to solve this kind of problem in future.   ;  What purpose does the function:IProperty* MakeProperty(const std::string &name, std::string value)Actually serve that the const std::string, const std::string version cannot do itself?   ;  alvaro has a point.The simple solution would be to have all parameter types passed by const reference:IProperty* MakeProperty(const std::string &name, const PropertyType& value)This will remove the ambiguity and provide the correct semantics for std::string parameters; there is the minor downside that you have to pass a const reference instead of a raw value for primitive types, but for the most part that should be a non-issue.The alternative is to abuse SFINAE and create a template overload that doesn't compile:#include <string>#include <iostream>template<typename T>class Foo{public:template<typename T2>void DoFoo(T2 blah){std::cout << blah << std::endl;}template<>void DoFoo(std::string blah){dontcompile();}void DoFoo(const std::string& blah){std::cout << "Const ref string " << blah << std::endl;}};int main(){Foo<int>().DoFoo(42);Foo<std::string>().DoFoo(std::string("Test"));}Since the compiler can't make the function DoFoo(std::string blah) compile, it will fall back on the next overload that works, which uses the const reference semantics you want.   ;  How about removing the MakeProperty(const string&, const string&) and changing to const references like MakeProperty(const string&, const PropertyValue&)?That way you could shift the whole problem to the MakerType::Set method, which could be overloaded for everything, that is not a string property.;  As yet another alternative, don't overload the name `MakeProperty', and make one of them something like `MakePropertyFromString'. The compiler is not the only one that gets confused when two functions share the same name: Programmers will also find it easier to know which function is being called if they have different names.   ;  Thanks for all the replies guys, I think alvaro just came up with the simplest solution tho, considering the usage I can get away with having MakePropertyString() and MakePropertyType() instead of a single overloaded functions.This is definatly a case of "your overthinking it, go have a coffee".I'm going to take a look at SPINAE as well, I've never come across it before.As always, thanks for the good help guys, Scott   ;  I think ApochPiQ's first solution is simpler:Quote:have all parameter types passed by const reference:Why can't you pass PropertyType by const reference?   ;  Hmmm, I dont think I was clear enough, my mistake, the class is defined:class PropertyMakerBase{};template<class MakerType, class PropertyType>class PropertyMaker : public PropertyMakerBase{};so therefore in the case of a template argument where PropertyType is std::string, the 2 function's created by the template would be:IProperty* MakeProperty(const std::string &name, const std::string &value);IProperty* MakeProperty(const std::string &name, const std::string &value);surely resulting in a redefinion error, or am I missing something?   