如何检查模板功能是否专用?

时间:2017-03-28 14:46:06

标签: c++ c++11 templates template-meta-programming template-specialization

如果某个模板函数是专用的,有没有办法在编译时建立?

例如,假设以下函数:

template<size_t N>
void foo();

我想测试foo<42>是否专业化。请注意,上面的声明不包含任何默认实现。

我尝试过SFINAE,但无法找到编译器无法从其声明中推断出的函数的条件。

有什么想法吗?

由于

1 个答案:

答案 0 :(得分:3)

  

如果某个模板函数是专用的,有没有办法在编译时建立?

有了一个功能......我不这么认为。

但是如果你创建一个仿函数,你可以添加一个静态const成员(在下面的例子中为is_specialized),它可以为你提供这些信息

#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
 }

---编辑---

遵循昆汀的建议(再次感谢!)我开发了另一种基于仿函数的解决方案,它使用某些东西来检测仿函数是通用的还是专门的,只在通用仿函数中添加。在这种情况下,类型为bool常量。

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; }
 };

此类型可以通过SFINAE使用,我提出了一个基于constexpr isSpecialized()模板函数(带辅助函数)的示例

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); }

这需要更多工作,但isSpecialized()可以与不同的仿函数(基于im_not_specialized类型)重复使用

以下是一个完整的工作示例

#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
 }