1

I've looked through a lot of posts that get the same error, but couldn't find one that applied to my problem, apologies if this is a duplicate regardless.

Anyway my task is making a class called set_helper which makes std::sets a little easier to use. set_helper takes a set as its constructor parameter, and to help with template type deduction I also have to make a function called make_set_helper that is supposed to make type deduction easier. I don't fully understand what that means, so here's what I tried.

MRE with main.cpp and sethelp.h

main.cpp

#include<set>
#include "sethelp.h"

int main()
{
    std::set<int, std::greater<int> > sg;
    sg.insert( 0 );
    sg.insert( 1 );

    make_set_helper( sg );
    return 0;
}

sethelp.h

#pragma once

template<class T>
class set_helper
{
private:
    std::set<T>* s;
public:
    set_helper(std::set<T>& s) { this->s = &s; }
    bool operator==(T other) { return this == other; }
    std::set<T>* get_set() {return this->s;}
};
template<class T>
set_helper<T> make_set_helper(std::set<T>& s)
{
    return set_helper(s);
}

Here's the error message

 error: no matching function for call to ‘make_set_helper(std::set<int, std::greater<int> >&)’
  108 |   make_set_helper( sg ) += sih;
 note: candidate: ‘template<class T> set_helper<T> make_set_helper(std::set<T>&)’
   79 | set_helper<T> make_set_helper(std::set<T>& s)
 note:   template argument deduction/substitution failed:
 note:   mismatched types ‘std::less<_Key>’ and ‘std::greater<int>’

Why are the types mismatched and what should I do to fix it?

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
devor110
  • 121
  • 8
  • 2
    please post a [mcve] instead of fragments. When I post an answer I want to post tested complete code. If you post your broken mre it is simple to fix, while as it looks now I would first solve the puzzle of setting your pieces together – 463035818_is_not_an_ai May 18 '21 at 15:12
  • Okay, just a sec – devor110 May 18 '21 at 15:14
  • 2
    `bool operator==(T other) { return this == other; }` is very suspicious... `T` should be `set_helper*` (not possible) or `void*`... – Jarod42 May 18 '21 at 15:25
  • I don't think I'm ever even using operator== (and it's also not required) so i'll just delete that, thanks for alerting me! – devor110 May 18 '21 at 15:28
  • What is the point of using `greater` in the type for `sg`? I don't see how that makes the resulting set any different. Reversing the order it stores them in doesn't make any difference to the use. – JDługosz May 18 '21 at 15:50
  • While I didn't write main.cpp, I assume its there to test the fullness of my solution. Another set_helper is later added to `sg` (using +=), but those parts were omitted as they weren't part of the mre. – devor110 May 18 '21 at 15:54
  • @JDługosz `std::greater` is just an example, OPs code would fail with any other custom comparator as well. Why one would use a custom comparator in the first place? Consider you want to have keys and the type itself has no `operator<` – 463035818_is_not_an_ai May 18 '21 at 18:07

2 Answers2

4

std::set<T> and std::set<T, std::greater<int>> are completely different types. Here's a more generic version:

template<
    class Key,
    class Compare = std::less<Key>,
    class Allocator = std::allocator<Key>
> 
auto make_set_helper(std::set<Key, Compare, Allocator>& s)
{
    return set_helper(s);
}

The class itself should also have all these template parameters. Alternatively:

template<class ...P> 
auto make_set_helper(std::set<P...>& s)
{
    return set_helper(s);
}
Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
  • I tried the above version, but the same issue still arises. Should I replace the in the class declaration with the set of 3 there too? – devor110 May 18 '21 at 15:30
  • @devor110 yes. As I pointed in the answer, you need to add these template arguments to the class too. If you want more help on that, you have to share more of your code (ie the class definition) – Aykhan Hagverdili May 18 '21 at 15:31
  • 2
    @devor110 See this https://gcc.godbolt.org/z/nK83hf9df – Aykhan Hagverdili May 18 '21 at 15:35
  • Thanks it's almost working now, just one more issue left. When One set_helper is made with the constructor with only Key defined, the other using make_set_helper with Key and Compare defined there's a mismatch for +='s operands, and the one defined in the constructor is only a std::set without Compare or Allocator specifically defined. What can I do to fix this? Here's the code of these functions: https://pastebin.com/un4sfDxP – devor110 May 18 '21 at 16:15
  • 2
    @devor110 https://gcc.godbolt.org/z/K9M44bvhv I think I did all of your homework :) – Aykhan Hagverdili May 18 '21 at 16:22
  • Close to that haha, but the previous issue still remains. I did some digging and I think it's actually arising from std::less and std::greater being incompatible between `sg` and `sih`. Is there a way for me to overload += so it can accept both std::greater and the defualt std::less? (btw I'm fine with an explanation/recommendation, you don't have to give me the correct code) – devor110 May 18 '21 at 17:13
  • 1
    @devor110 the explanation is that you need to make those operators templated too: https://gcc.godbolt.org/z/jxWh9zrs4 – Aykhan Hagverdili May 18 '21 at 17:23
  • 1
    @devor110 this version is more compact. But you have to know about variadic templates https://gcc.godbolt.org/z/zqEx9K7G9 – Aykhan Hagverdili May 18 '21 at 17:31
2

std::set takes three template parameter. When you only specify the first one, the second (comparator) and third (allocator) is the default. So std::set<T> is short for std::set<T,std::less<T>,std::allocator<T>>. If you want to accept sets with different comparators, use both template parameter:

#include <set>


template <typename T,typename Compare>
void foo(std::set<T,Compare>& x){}

template <typename T>
void bar(std::set<T>& x){}

int main(){
    std::set<int> a;
    std::set<int,std::greater<int>> b;
    foo(a);
    foo(b);
    bar(a);      // ok
    //bar(b);    // error
}
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185