Shankaran Madhavan
Shankaran Madhavan

Reputation: 23

build issue with make_tuple - arrary reference

I've a class which takes a reference to an array of size 5 as one of the parameter in the constructor.

class sha1 {
public:
    typedef unsigned int(&type)[5];
    type digest_;
    sha1(const type digest) : digest_(digest)
    {}
};

I am able to instantiate this class by passing an array of 5. But replacing that with a call to std::make_tuple fails to compile.

int main(int argc, const char* const argv[]) {
    unsigned int digest[5] = { 0 };
    const sha1 s(digest);
    const sha1 p = std::make_tuple(digest);   <-- error here
    return 0;
}

Error:

error C2440: 'initializing': cannot convert from 'std::tuple<unsigned int *>' to 'sha1'
note: No constructor could take the source type, or constructor overload resolution was ambiguous

How can I make this work? Code here has been simplified a lot to make it easier to explain. What I am trying to do is to use the class as a key to unordered_map and use emplace to insert entries, which gives the same error.

I am using Visual Studio 2015

Here is the code with unordered_map

#include <iostream>
#include <unordered_map>

class sha1 {
public:
    typedef unsigned int(&type)[5];
    const type digest_;
    const int index_;
    sha1(const type digest, int index) : digest_(digest), index_(index)
    {}
    bool operator==(const sha1& that) const {
        return true;
    }
};

namespace std {
    template<> struct hash<sha1> {
        inline size_t operator()(const sha1& p) const {
            return 0;
        }
    };
}

int main(int argc, const char* const argv[]) {
    unsigned int digest[5] = { 0 };

    const sha1 s(digest, 10); // works

    std::unordered_map<sha1, std::string> map;

    map.insert(std::make_pair(sha1(digest, 10), "test")); // works

    map.emplace(std::piecewise_construct, std::make_tuple(digest, 10), std::make_tuple("test"));  // <-- error here

    return 0;
}

Upvotes: 2

Views: 455

Answers (1)

Praetorian
Praetorian

Reputation: 109289

make_tuple will decay the arguments you pass to it before constructing the tuple, so the unsigned int(&)[5] type is converted to unsigned int *, which does not match your sha1 constructor's parameter type.

Use forward_as_tuple instead to create a tuple of references.

map.emplace(std::piecewise_construct,
            std::forward_as_tuple(digest, 10),
            std::forward_as_tuple("test"));

Upvotes: 2

Related Questions