1

I am creating a function like such:

void SetItem(const Key &key, const Value &value)
{
    ...
}

Where Key and Value are some type.

Internally, I want to store the pair like this:

std::pair<const Key &, Value>

So here is my problem: I need to enforce that Key is actually an l-value so that it doesn't get cleaned up when the function exits (Unsafe with r-values)

I could make the signature to the function:

void SetItem(Key &key, const Value &value)

Which would prevent the use of r-values, but it then doesn't allow a const key to be used, which I don't like either.

Is there a way for me to force Key to be an l-value while preserving the constness?

I am fine with creating an r-value overload to prevent it:

void SetItem(Key &&key, const Value &value)
{
     [What do I put here?]
}

Thanks

Mranz
  • 1,260
  • 1
  • 12
  • 20

2 Answers2

5

With the improvements from the comments incorporated, it should look like this in a fully conformant C++11 compiler:

class X{
public:
  void SetItem(Key const& key, Value const& value);
private:
  void SetItem(Key const&&, Value const&) = delete;
};

The private overload will catch all Key rvalues. Access checking isn't done during overload resolution, as such we can put it under private, and so that possible friends also get a nice error message at compile time, we = delete it.

For compilers that don't support explicitly deleted functions yet, you can leave it simply undefined, but that will only show up as a linker error for possible friends. However, the general audience will get the nice "`SetItem' is inaccessible" compiler error message. :)

Xeo
  • 129,499
  • 52
  • 291
  • 397
3

Besides @Xeo's answer, you can also do

template<typename T = int> // thanks to Xeo for suggesting the default parameter
void SetItem(Key&& key, const Value& value) {
    static_assert(sizeof(T) == 0, "SetItem cannot be used with temporary values as keys");
}

This has the advantage over leaving the function undefined of providing the given error message at compile time, rather than getting an unhelpful linker error.

Note that the static_assert must depend on the template parameter so that it only errors when it is used. Otherwise the compiler is free to compile it even when it's not called anywhere and it will error all the time.

Seth Carnegie
  • 73,875
  • 22
  • 181
  • 249
  • I thought about doing this, but then the second parameter isn't explicit, which makes the interface seem unhelpful. It is still a good alternative so I voted it up. Thanks for the help. – Mranz Jan 27 '12 at 00:45
  • @Mranz I don't think it makes the interface seem unhelpful. To me, it indicates that the problem is with the type of the key, not the type of the value. – Seth Carnegie Jan 27 '12 at 00:46
  • I guess what I mean by unhelpful is that then the user has to know that even though I accept anything, I am expecting T to actually be Value, and if it isn't, I get different crazy compiler errors. – Mranz Jan 27 '12 at 00:48
  • 1
    You might also do this with a defaulted template parameter IIRC. – Xeo Jan 27 '12 at 00:49
  • @Xeo that's way better and satisfies the problem the OP had, thanks very much. – Seth Carnegie Jan 27 '12 at 00:51
  • @Mranz see if now with Xeo's suggestion it's any better – Seth Carnegie Jan 27 '12 at 00:52
  • 1
    [Here's a testcase](http://ideone.com/6lw1A), comment out the function call and it compiles fine. – Xeo Jan 27 '12 at 00:52
  • You have the best answer now. Unfortunately for me, msvc doesn't support default template arguments for functions, so I can't make this work. That being said, I didn't constraint my question to msvc, and your answer is definitely elegant at producing a meaningful error. I will keep this in mind for when MS decides c++ is still important. – Mranz Jan 27 '12 at 01:04
  • @Mranz wow, that's stupid of VS, it only supports default template parameters on class templates, not function templates. Please consider reaccepting Xeo's answer because it's the only one you can use. I will leave this answer here so future readers can use it if their compiler supports it. Plus, this is only an acceptable answer because of what Xeo suggested anyway. – Seth Carnegie Jan 27 '12 at 01:07
  • @Seth : Default template arguments for function templates are a C++11 feature; VC++ 2010 predates C++11's standardization so it's a bit unfair to criticize it for not having that implemented yet. ;-] – ildjarn Jan 27 '12 at 16:02
  • 1
    @ildjarn VC11 doesn't support it either. So we are allowed to be harsh. – Mranz Jan 27 '12 at 16:17
  • @Mranz : VC11 _preview_ doesn't support it, but don't be so sure. – ildjarn Jan 27 '12 at 16:20
  • 1
    @ildjarn It is basically confirmed that what is in preview is what will be in release. Better C++11 support may show up in SP1. Herb Sutter confirmed this in BUILD. – Mranz Jan 27 '12 at 16:45
  • No sizeof value is ever 0, so the compiler can still give the error even if it is not used (or give a warning "static-cast condition will always evaluate to false"). Better use something like `always_false::value`. – Johannes Schaub - litb Jan 28 '12 at 14:18
  • In any case, you can use `template void SetItem(Key&& key, const Value& value) { static_assert(sizeof...(T) != 0, "..."); }` on MSVC, I suspect. `T` will default to be an empty pack. – Johannes Schaub - litb Jan 28 '12 at 14:21
  • 2
    @Johannes: No variadic templates in MSVC10 and 11 (yet). :( – Xeo Jan 28 '12 at 14:36
  • @JohannesSchaub-litb actually I'm pretty sure the compiler isn't allowed to do that until the template is instantiated. I've seen `sizeof(T) == 0` a lot of places, namely [here](http://stackoverflow.com/a/8305540/726361), [here](http://stackoverflow.com/a/2155779/726361), [here](http://stackoverflow.com/a/1629417/726361), and [here](http://stackoverflow.com/a/2836972/726361), and also in a lot of comments by the smarter people here on SO, among others which I can't find – Seth Carnegie Jan 28 '12 at 17:14
  • @Seth you are pretty sure, but I'm totally sure that it *is* allowed to reject the template even if it is not instantiated. Those places are all broken, I'm sorry. – Johannes Schaub - litb Jan 28 '12 at 19:24