-1

The Pairwise class represents a pair with a key:value. I've made a template pair and was having errors trying to run with a key and value input to the class and printing it out.

Given my main:

#include "file_name.h"

int main (){
    Pairwise<string, string> example = {{"key", "value"}};
    cout << example << endl;
 }

And my header file:

#pragma once

#include<iostream>
using std::ostream; using std::cout; using std::endl;
#include<string>
using std::string;
#include<utility>
using std::pair;
#include<sstream>
using std::ostringstream;

template<typename K, typename V>
struct Pairwise{
    K first;
    V second;
    Pairwise() = default;
    Pairwise(K, V);
    //print out as a string in main
    friend ostream& operator<<(ostream &out, const Pairwise &n) {
        ostream oss;
        string s;
        oss << n.first + ":" + n.second; //possible error?
        s = oss.str();
        out << s; 
        return out;
    }
};

My expected output after running main would be:

key:value

However, I am getting the error:

h:28:11: error: 'std::basic_ostream<_CharT, _Traits> is protected within..."
Swordfish
  • 12,971
  • 3
  • 21
  • 43
Dracep
  • 388
  • 2
  • 13
  • That stream inserter is a bit convoluted. `out << n.first << ":" << n.second; return out;` is sufficient. In fact, I'd just write it as a one-liner: `return out << n.first << ':' << n.second;`, but some folks like to be more verbose. – Pete Becker Nov 23 '18 at 17:55
  • 1
    `ostream oss;` is a typo, right? Should be `ostringstream oss;`. And the error message is truncated. Don't summarize; post the smallest code you can come up with that shows the problem, and quote the **entire** error message. There's nothing protected here, so that bit of the error message needs context in order to make any sense. – Pete Becker Nov 23 '18 at 18:02
  • besides it is needlessly complicated ... *`oss << n.first + ":" + n.second;`* – Why `+`? That limits its functionality to types that support `+` for itself and string literals. – Swordfish Nov 23 '18 at 18:07
  • @PeteBecker Awesome, shortened code is always helpful to me! – Dracep Nov 23 '18 at 18:07
  • @Swordfish Thanks for pointing the '+' operator out. I'm always looking for ways to improve my code. Do you think my main function looks fine as it is? Passing in the values to the template class – Dracep Nov 23 '18 at 18:09
  • Why the double curly braces? `Pairwise example{"key", "value"};` would be sufficient. – Swordfish Nov 23 '18 at 18:10
  • Why do you *`#include using std::string; #include using std::pair;`* in your header file? `` should be included by the user of that header file if it wants to use `Pairwise` with `std::string`s. And why ``? – Swordfish Nov 23 '18 at 18:20
  • @Swordfish got it, I have made an edit to my post – Dracep Nov 23 '18 at 18:24
  • All members are `public`. So, why do you think you would need `friend`? – Adrian W Nov 23 '18 at 18:28
  • Don't edit your posted code on the fly. You **do** need `#include ` somewhere, because your `main` function uses `std::string`. **Try it** before you post it. – Pete Becker Nov 23 '18 at 18:37
  • @AdrianW I agree with Pete Becker, don't alter the code in the question. Now the error message you included which was caused by your original code makes no sense at all. – Swordfish Nov 23 '18 at 18:44

3 Answers3

1

As you write it, you define the operator as a member function, which is very likely not intended. Divide it like ...

template<typename K, typename V>
struct Pairwise{
    K first;
    V second;
    Pairwise() = default;
    Pairwise(K, V);
    //print out as a string in main
    friend ostream& operator<<(ostream &out, const Pairwise &n);
};

template<typename K, typename V>
ostream& operator<<(ostream &out, const Pairwise<K,V> &n) {
    ...
    return out;
}

And it should work.

BTW: Note that in a struct all members are public by default; so you would be able to access them even in absence of the friend-declaration.

Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58
  • 1
    With the template before the operator – Matthieu Brucher Nov 23 '18 at 17:51
  • Isn't there a `template` missing in front of the friend-declaration? e.g `template friend ostream& operator<<(ostream &out, const Pairwise &n);` ? – Swordfish Nov 23 '18 at 18:02
  • Thank you very much, this cleared up my understanding of friend operator! By the way, could you take a quick glance at my main? If the values are passed in correctly – Dracep Nov 23 '18 at 18:06
  • *As you write it, you define the operator as a member function* – A definition with `friend` never defines a member. – Swordfish Nov 23 '18 at 18:15
  • @Swordfish is that referring to the warning that "h:25:59: friend declaration delares a non template function...". Do you mind writing in another answer post how you would implement that change? It seems that this causes me to not exactly print out my output "key:value" – Dracep Nov 23 '18 at 18:29
  • @Dracep *is that referring to the warning that [...]* – yes. I wrote another answer. – Swordfish Nov 23 '18 at 18:54
  • The answer of @Swordfish is much better. If I were you, I'd accept the other answer. – Stephan Lechner Nov 23 '18 at 18:59
1

h:25:59: friend declaration delares a non template function.

You are missing to declare the function as a template that takes Pairwise<K, V>:

header.h:

#ifndef HEADER_H_INCLUDED  /* or pragma once */
#define HEADER_H_INCLUDED  /* if you like it */

#include <iostream>  // or <ostream>

template<typename K, typename V>
class Pairwise {  // made it a class so that the
    K first;      // friend actually makes sense.
    V second;

public:
    Pairwise() = default;

    Pairwise(K first, V second)
    : first{ first }, second{ second }
    {}

    template<typename K, typename V>
    friend std::ostream& operator<<(std::ostream &out, Pairwise<K, V> const &p)
    {
        return out << p.first << ": " << p.second;
    }
};

#endif /* HEADER_H_INCLUDED */

source file:

#include <iostream>  // the user can't know a random header includes it
#include <string>

#include "header.h"

int main()
{
    Pairwise<std::string, std::string> p{ "foo", "bar" };
    std::cout << p << '\n';
}

Sidenote: You could also use

{
    using Stringpair = Pairwise<std::string, std::string>;
    // ...
    Stringpair sp{ "foo", "bar" };
}

if you need that more often.

The other errors you got result from confusing std::ostringstream with std::ostream in operator<<().

Swordfish
  • 12,971
  • 3
  • 21
  • 43
0

In c++, less is often more...

#pragma once

#include<iostream>
#include<string>

// never do this in a header file:
// using std::ostream; 

template<typename K, typename V>
struct Pairwise{
    K first;
    V second;
    Pairwise() = default;
    Pairwise(K, V);
    //print out as a string in main
    friend std::ostream& operator<<(std::ostream &out, const Pairwise &n) {
        return out << n.first << ':' << n.second;
    }
};

int main (){
    using std::cout; using std::endl; using std::string;

    Pairwise<string, string> example = {"key", "value"};
    cout << example << endl;
 }

https://godbolt.org/z/ZUlLTu

Richard Hodges
  • 68,278
  • 7
  • 90
  • 142