Clang and GCC differently when resolving overload of variational function patterns

Consider this code:

#include <utility>

int foo_i(int x) { return x + 1; }
char foo_c(char x) { return x + 1; }

using II = int (*)(int);
using CC = char (*)(char);

template<typename F>
struct fn {
    F f;

    template<typename... Args>
    decltype(auto) operator()(Args&&... args) const
    {
        return f(std::forward<Args>(args)...);
    }
};

struct fn_2 : private fn<II>, private fn<CC> {
    fn_2(II fp1, CC fp2)
        : fn<II>{fp1}
        , fn<CC>{fp2}
    {}

    using fn<II>::operator();
    using fn<CC>::operator();
};

int main()
{
    fn_2 f(foo_i, foo_c);

    f(42);
}

In principle, it fn<T>stores a functor (not necessarily a function pointer) of the type T, and its variational operator()translates everything into a functor.

This code compiles with gcc 4.9.2 through gcc 6.1 , but is rejected by every version of clang I tried, even clang 3.8 . clang complains that the call is ambiguous. (I would appreciate it if someone tries to compile it with VS, because I don't have access to it right now.)

Which compiler is right, and how can I get around this mismatch?

: , () , : fn<T> operator(). (, -... .:/) :

template<typename F>
struct fn : private F {
    using F::operator();
};

template<typename R, typename... Args>
struct fn<R (*)(Args...)> {
    fn(R (*f)(Args...)) noexcept : f_(f) {}

    R operator()(Args&&... args) const
    {
        return f_(std::forward<Args>(args)...);
    }

private:
    R (*f_)(Args...);
};
+4
3

, clang , , operator() . , operator() , . fn.

:

#include <utility>
#include <type_traits>
#include <iostream>

int foo(int x) { return x + 1; }
char foo(char x) { return x + 1; }

using II = int (*)(int);
using CC = char (*)(char);

template <bool... B>
struct bool_pack {};

template <bool... V>
using all_true = std::is_same<bool_pack<true, V...>, bool_pack<V..., true>>;

template <typename... Args> struct packed {};

template <typename T> struct func_traits;

template <typename R, typename... Args>
struct func_traits<R(*)(Args...)> {
        using type = packed<Args...>;
};

template<typename F>
struct fn {
  F f;

  template<typename... Args,
           typename std::enable_if<std::is_same<packed<Args...>, typename func_traits<F>::type>::value>::type* = nullptr>
  auto operator()(Args&&... args) const
  {
    return f(std::forward<Args>(args)...);
  }
};

struct fn_2 : private fn<II>, private fn<CC> {
  fn_2(II fp1, CC fp2)
    : fn<II>{fp1}
    , fn<CC>{fp2}
  {}

  using fn<II>::operator();
  using fn<CC>::operator();
};

int main()
{
  fn_2 f(static_cast<II>(foo),
         static_cast<CC>(foo));

  std::cout << f(42) << std::endl;
  std::cout << f('a') << std::endl;
}

, enable_if, operator() arty .

+2

GCC. , GCC fn<II>, char. , , , GCC .

+2

, char int - . , char int (, int char !), . GCC , , .

EDIT: , , operator(). , .

0

Source: https://habr.com/ru/post/1647997/


All Articles