Daniel
Daniel

Reputation: 311

Why is my forward to std::make_pair in a separate namespace ambiguous?

Disclaimer: This is more or less for educational purposes, so a discussion about the meaningfulness of the shown wrapping should be neglected.

Consider the following template in its own namespace:

// file my_make_pair.h

#pragma once
#include <utility>

namespace fc {

    template<typename T, typename U>
    decltype(auto) make_pair(T&& first, U&& second)
    {
        return std::make_pair(std::forward<T>(first),
                              std::forward<U>(second));
    }

}

When I try to use it from within this namespace:

// file my_test.cpp

#include "my_make_pair.h"
#include <string>

namespace fc {

    void my_function(const std::string& name) {
        auto my_pair = make_pair(name, 42);
    }

}

I get the following compiler error:

could be 'decltype(auto) fc::make_pair<const std::string&,int>(T,U &&)'
    with
    [
        T=const std::string &,
        U=int
    ]

or 'std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,int> std::make_pair<const std::string&,int>(_Ty1,_Ty2 &&)'
                     [found using argument-dependent lookup]
    with
    [
        _Ty1=const std::string &,
        _Ty2=int
    ]

As soon as I rename my wrapper to something else, e.g. make_my_pair, everything works.

It also seems to be related to the const reference parameter of fc::my_function which I use for the first value of the pair. When I change the call to my wrapper to just use (primitive) rvalues, e.g. auto my_pair = fc::make_pair(1.42, 42);, everything works. It also works, when I directly use std::make_pair.

Why does the compiler take the implementation of the std namespace into account in the first place? I did not explicitly use std::make_pair (with the exception of the wrapper definition) nor did I do using namespace std at any time. I am using Visual Studio 2015 (VC14).

Upvotes: 0

Views: 346

Answers (1)

piwi
piwi

Reputation: 5336

The call is ambiguous because of Argument Dependent-name Lookup (ADL). Because your argument is a std::string, then the make_pair() in namespace std is considered.

This is why, for example when you call std::cout << 21, you do not need to specify the namespace std for operator<<: because of ADL it is figured by the compiler.

If you want to enforce that your own implementation is used, then you need to prefix the call with the namespace fc::make_pair(...).

Upvotes: 2

Related Questions