Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if a template function was specialized?

Tags:

Is there a way to establish at compile time if a certain function template was specialized?

For example, assume the following function template:

template<size_t N>
void foo();

I want to test if foo<42> was specialized. Note that the declaration above doesn't contain any default implementation.

I tried SFINAE but couldn't find a condition on the function that the compiler cannot deduce from its declaration.

like image 429
Mr. Anderson Avatar asked Mar 28 '17 14:03

Mr. Anderson


People also ask

What is function template specialization?

The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.

Are template specializations inline?

An explicit specialization of a function template is inline only if it is declared with the inline specifier (or defined as deleted), it doesn't matter if the primary template is inline.

How can you differentiate a function template from a class template?

For normal code, you would use a class template when you want to create a class that is parameterised by a type, and a function template when you want to create a function that can operate on many different types.

What is the difference between normal function and template function?

What is the difference between normal function and template function? Explanation: As a template feature allows you to write generic programs. therefore a template function works with any type of data whereas normal function works with the specific types mentioned while writing a program.


1 Answers

Is there a way to establish in compile time if a certain template function was specialized?

With a function... I don't think so.

But if you create a functor, you can add a static const member (is_specialized, in the following example) that can give you this information

#include <iostream>

template <std::size_t N>
struct foo
 {
   static constexpr bool is_specialized { false };

   void operator() () const
    { std::cout << "- generic (" << N << ") foo struct" << std::endl; }
 };

template <>
struct foo<42U>
 {
   static constexpr bool is_specialized { true };

   void operator() () const
    { std::cout << "- specialized (42) foo struct" << std::endl; }
 };

int main()
 {
   foo<17U>()(); // print - generic (17) foo struct
   foo<42U>()(); // print - specialized (42) foo struct

   std::cout << foo<17U>::is_specialized << std::endl; // print 0
   std::cout << foo<42U>::is_specialized << std::endl; // print 1
 }

--- EDIT ---

Following the suggestion from Quentin (thanks again!) I've developed another functor-based solution that use something, to detect if the functor is generic or specialize, that is added only in the generic functor. In this case, a type instead a bool constant.

template <std::size_t N>
struct foo
 {
   // im_not_specialized is added only in the generic version!
   using im_not_specialized = void;

   void operator () () const
    { std::cout << "- generic (" << N << ") foo struct" << std::endl; }
 };

template <>
struct foo<42U>
 {
   void operator () () const
    { std::cout << "- specialized (42) foo struct" << std::endl; }
 };

This type can be used via SFINAE and I propose an example based on a constexpr isSpecialized() template function (with an helper function)

template <typename F>
constexpr bool isSpecializedHelper
      (int, typename F::im_not_specialized const * = nullptr)
 { return false; }

template <typename F>
constexpr bool isSpecializedHelper (long)
 { return true; }

template <typename F>
constexpr bool isSpecialized ()
 { return isSpecializedHelper<F>(0); }

This require a little more work but isSpecialized() can be reused with different functors (im_not_specialized type based)

The following is a full working example

#include <iostream>

template <std::size_t N>
struct foo
 {
   // im_not_specialized is added only in the generic version!
   using im_not_specialized = void;

   void operator () () const
    { std::cout << "- generic (" << N << ") foo struct" << std::endl; }
 };

template <>
struct foo<42U>
 {
   void operator () () const
    { std::cout << "- specialized (42) foo struct" << std::endl; }
 };

template <typename F>
constexpr bool isSpecializedHelper
      (int, typename F::im_not_specialized const * = nullptr)
 { return false; }

template <typename F>
constexpr bool isSpecializedHelper (long)
 { return true; }

template <typename F>
constexpr bool isSpecialized ()
 { return isSpecializedHelper<F>(0); }

int main()
 {
   foo<17U>()(); // print - generic (17) foo struct
   foo<42U>()(); // print - specialized (42) foo struct

   constexpr auto isSp17 = isSpecialized<foo<17U>>();
   constexpr auto isSp42 = isSpecialized<foo<42U>>();

   std::cout << isSp17 << std::endl; // print 0
   std::cout << isSp42 << std::endl; // print 1
 }
like image 83
max66 Avatar answered Sep 24 '22 10:09

max66