Why can we detect the presence of default parameter values of operator() with SFINAE, but not those of free functions and PMFs?

隐身守侯 提交于 2019-12-11 11:13:57

问题


In the program below, case 1 attempts to use a default parameter via pointer-to-member-function. Case 2 attempts to use a default parameter via function reference. Case 3 uses the default parameter in operator(). The only interesting assertions here are the ones using the alias can_call_with_one - the others exist to prove correctness of the setup.

In the latest versions of GCC, Clang, and MSVC that are available to me, this program fails the single-argument assertions in cases 1 and 2.

My question is twofold:

  1. Are these results consistent with the ISO C++ standard?
  2. If so, why does case 3 not fail?
#include <type_traits>
#include <utility>

struct substitution_failure {};

substitution_failure check(...);

template<typename Pmf, typename T, typename... Args>
auto check(Pmf pmf, T t, Args&&... args) ->
    decltype((t.*pmf)(std::forward<Args>(args)...))*;

template<typename Fn, typename... Args>
auto check(Fn&& f, Args&&... args) ->
    decltype(f(std::forward<Args>(args)...))*;

template<typename T>
using test_result = std::integral_constant<bool,
    !std::is_same<T, substitution_failure>::value
>;

template<typename... Ts>
auto can_invoke(Ts&&... ts) ->
    test_result<decltype(check(std::forward<Ts>(ts)...))>;

namespace case_1 {

    //pointer to member function

    struct foo {
        int bar(int, int = 0);
    };

    using can_call_with_one = decltype(can_invoke(&foo::bar, foo{}, 0));
    using can_call_with_two = decltype(can_invoke(&foo::bar, foo{}, 0, 0));
    using can_call_with_three = decltype(can_invoke(&foo::bar, foo{}, 0, 0, 0));

    static_assert(can_call_with_one{}, "case 1 - can't call with one argument");
    static_assert(can_call_with_two{}, "case 1 - can't call with twp arguments");
    static_assert(!can_call_with_three{}, "case 1 - can call with three arguments");
}

namespace case_2 {

    //function reference

    int foo(int, int = 0);

    using can_call_with_one = decltype(can_invoke(foo, 0));
    using can_call_with_two = decltype(can_invoke(foo, 0, 0));
    using can_call_with_three = decltype(can_invoke(foo, 0, 0, 0));

    static_assert(can_call_with_one{}, "case 2 - can't call with one argument");
    static_assert(can_call_with_two{}, "case 2 - can't call with two arguments");
    static_assert(!can_call_with_three{}, "case 2 - can call with three arguments");
}


namespace case_3 {

    //function object

    struct foo {
        int operator()(int, int = 0);
    };

    using can_call_with_one = decltype(can_invoke(foo{}, 0));
    using can_call_with_two = decltype(can_invoke(foo{}, 0, 0));
    using can_call_with_three = decltype(can_invoke(foo{}, 0, 0, 0));

    static_assert(can_call_with_one{}, "case 3 - can't call with one argument");
    static_assert(can_call_with_two{}, "case 3 - can't call with two arguments");
    static_assert(!can_call_with_three{}, "case 3 - can call with three arguments");
}

int main() { return 0; }

runnable version


回答1:


Type trait of the function does not come with the information of the default parameters. If it would you wouldn't be able to assign a pointer of a function with default value like:

void foo(int, int = 0) {...}

to:

void(*fp)(int, int);
fp = &foo;

The question is now if the language would allow for that - should the values that are default for a given parameters also identify the type of a function? This would imply that the default value of the parameter should be a constexpr, and as such would restrict the usability of the default values. This way for example parameters of type const char * couldn't have default value defined inline...

On the other hand if the type of the function would carry only the information that a given parameter has a default value without the knowledge of the value itself - compiler wouldn't be able to reconstruct the default value of the function from the pointer while the function invocation.



来源:https://stackoverflow.com/questions/35966588/why-can-we-detect-the-presence-of-default-parameter-values-of-operator-with-sf

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!