1

(This question has been significantly edited, sorry.)

Suppose I have several non-constexpr function templates, which default to being deleted:

template <typename T> void foo() = delete;
template <typename T> int  bar(int x) = delete;
// etc.

and have some explicit specialization as an exception to the general-case deletion.

I want to write code (e.g. a trait class?) which, given the identifier of one of these functions and a type T, detects, at compile-time, whether the specified function is explicitly specialized for type T. The code needs to be generic, i.e. not a separate detector for each of the functions.

Notes:

  • Looking for a C++11 solution.
  • We may assume the specified function is deleted by default - if that helps.
  • Ideally, it would like like instantiation_exists<decltype(foo), foo, int>::value or instantiation_exists<int>(foo, tag<int>) or instantiation_exists(foo, tag<int>) or something along those lines.

Edit: @Jarod42's wrote up an SFINAE example in a comment on an earlier version of this question, which was about a per-single-function detector. I tried to generalize/genericize it using a template-template parameter:

#include <type_traits>

template <typename T> void foo() = delete;
template <> void foo<int>() {}

template <template<typename U> typename F, typename T, typename = decltype(F<T>()) >
std::true_type test(int);

template  <template<typename U> typename F, typename T>
std::false_type test(...);

template <typename T>
using foo_is_defined = decltype(test<foo<T>, T>(0));

static_assert(foo_is_defined<int>::value);
static_assert(not foo_is_defined<int*>::value);

but that was a wash (Coliru).

walnut
  • 21,629
  • 4
  • 23
  • 59
einpoklum
  • 118,144
  • 57
  • 340
  • 684

1 Answers1

1

We cannot pass template function, or overloads in template parameter.

We can turn those function in functor:

template <typename T>
struct identity_type
{
    using type = T;  
};

template <typename F, typename T, typename = decltype(std::declval<F>()(identity_type<T>{})) >
std::true_type test(int);

template  <typename F, typename T>
std::false_type test(...);

auto foos = [](auto tag, auto&&... args)
-> decltype(foo<typename decltype(tag)::type>((decltype(args))(args)...))
{
    return foo<typename decltype(tag)::type>((decltype(args))(args)...);
};

template <typename T>
using is_foo = decltype(test<decltype(foos), T>(0));

Demo

I use generic lambda, so C++14.

in C++11, it would be really verbose:

struct foos
{
    template <typename T, typename... Ts>
    auto operator()(identity_type<T>, Ts&&... args) const
    -> decltype(foo<T>(std::forward<Ts>(args)...))
    {
        return foo<T>(std::forward<Ts>(args)...);
    };
};
Jarod42
  • 203,559
  • 14
  • 181
  • 302