Home > Blockchain >  Why does t =i 'a' give the correct output while t=t i 'a' gives an error?
Why does t =i 'a' give the correct output while t=t i 'a' gives an error?

Time:06-10

I have been working on some question that involves converting ASCII value into string.

If I use this code, I get output as g, which is expected.

using namespace std;
int main()
{
    int i=6; vector<string> ans;
    string t= "";

    t =i 'a';

    ans.push_back(t);
    cout<<ans[0];
    return 0;
}

However, If I change the code like this:

using namespace std;
int main()
{
    int i=6; vector<string> ans;
    string t= "";

    t=t i 'a';        // <----

    ans.push_back(t);
    cout<<ans[0];

    return 0;
}

The following error is shown, when I try to compile it:

error: no match for 'operator ' (operand types are 'std::string' {aka 'std::__cxx11::basic_string<char>'} and 'int')

7 | t=t i 'a';
  |   ~^~
  |   | |
  |   | int
  |   std::string {aka std::__cxx11::basic_string<char>}

The only difference between both the code is that in 1st code, I am using t =i 'a';, while in second, t=t i 'a'; is used.

Can someone please tell what is wrong with the second snippet?

CodePudding user response:

1. The t = i 'a'; case

Here, two things are important. First,

std::string& std::string::operator =(char ch);

is called, which is a non-template member function of the std::string class (that is, of the std::basic_string<char> class template instance); see https://en.cppreference.com/w/cpp/string/basic_string/operator+=.

Second, the type of i 'a' is int.

Everything works fine, since the argument i 'a' of type int can be used as an argument for a function parameter of type char.

2. The t = t i 'a'; case

In contrast to case 1., operator is used here. First for the t i part, where i is of type int (see @AnoopRana's answer for details of why). But opeartor is a free (non-member) function template; see https://en.cppreference.com/w/cpp/string/basic_string/operator+.

The compiler tries to instantiate this definition:

template<class CharT, class Traits, class Alloc>
std::basic_string<CharT,Traits,Alloc>
operator ( const std::basic_string<CharT,Traits,Alloc>& lhs, CharT rhs );

But it can't since:

  1. according to the first argument of type std::string, CharT would be deduced as char,
  2. according to the second argument of type int, CharT would be deduced as int.

Therefore, duduction conflict happens. And, there is no other template that might be instantiated.


Simple demo code of the same problem:

template <typename Char>
struct String
{
    String& operator =(Char);
};

template <typename Char>
String<Char> operator (const String<Char>&, Char);

int main()
{
    String<char> s;
    s  = 2   'a';
    s = s   2   'a';
}

Live link: https://godbolt.org/z/MonK1e3bq

CodePudding user response:

The problem in case 2 is that the statement t = t i 'a' is actually grouped as(or equivalent to) t = (t i) 'a' due to operator precedence.

//---v---v--------->t is std::string while i is an int
t = (t   i)   'a'; //equivalent to this due to operator precedence

Now as t is a std::string and i is an int and since there is no overloaded operator that takes an std::string and a int, we get the mentioned error.


Note that is an arithmetic operator and so in the first case, the character literal 'a' is promoted to int when writing i 'a'. And since std::string has the overload string& string::operator = (char) that can be used, the first case uses that overloaded operator =.

  • Related