为什么我不能专门使用依赖类型的nullptr模板参数?

时间:2015-08-19 13:56:11

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

我想对一个结构进行专门化,其中一个使用函数指针而另一个不使用。但是,当我这样做时:

template <typename T, T*>
struct test;

template <typename T>
struct test<T, nullptr>
{
};

template <typename R, typename...ARGs, R(*fn)(ARGs...)>
struct test<R(ARGs...), fn>
{
};

我收到此错误:

error: type 'T*' of template argument 'nullptr' depends on a template parameter                                                                                                                                                   
 struct test<T, nullptr>

这究竟是什么意思,我该如何运作?

1 个答案:

答案 0 :(得分:4)

linked question描述了主要问题和一些解决方案,但由于它非常复杂,我已将它们应用于您的特定问题。

版本1

我们实际上可以使用std::integral_constant来保存指针,因此我们可以利用这个事实来解决对非类型参数的限制:

template <typename T, typename U>
struct test;

template <typename T>
struct test<T, std::integral_constant<T*,nullptr>>
{
    void operator()() { std::cout << "nullptr" << std::endl; }
};

template <typename R, typename...ARGs, R(*fn)(ARGs...)>
struct test<R(ARGs...), std::integral_constant<R(*)(ARGs...),fn>>
{
    void operator()() { std::cout << "fnptr" << std::endl; }
};

不幸的是,这种用法看起来很丑陋,但它确实有效:

test<int,std::integral_constant<int*,nullptr>> a;
a();
test<decltype(foo), std::integral_constant<decltype(&foo), foo>> b;
b();

版本2

此版本使用std::enable_if进行检查而非部分专业化:

template <typename T, T*, typename = void>
struct test;

template <typename T, T* P>
struct test<T, P, typename std::enable_if<(P==nullptr)>::type>
{
    void operator()() { std::cout << "nullptr" << std::endl; }
};

template <typename T, T* P>
struct test<T, P, typename std::enable_if<std::is_function<T>::value>::type>
{
    void operator()() { std::cout << "fnptr" << std::endl; }
};

这可能是你最初的意图:

test2<int, nullptr> c;
c();
test2<decltype(foo), foo> d;
d();

使用此版本,您无法即时访问用作模板参数的函数指针的参数类型,但如果需要,您可以轻松编写其他特征以获取它们。

这里有一个Live Demo,显示两个版本都在运行。