是否可以使用模板元编程有条件地禁用全局函数定义?

bgo*_*dst 5 c++ templates conditional-compilation template-meta-programming

假设我有一个简单的nullary模板函数模板化在一个参数上,有两个特化,一个用于unsigned long,一个用于size_t(内容不重要):

template<typename T> T f(void);
template<> unsigned long f<unsigned long>(void) { return 1; }
template<> size_t f<size_t>(void) { return 2; }
Run Code Online (Sandbox Code Playgroud)

我的理解是该类型的确切定义size_t是依赖于平台的,因此它可能相同或不相同unsigned long.在我目前的平台上(Cygwin g ++ 5.2.0在Windows 10上进行64位编译-std=gnu++1y)这两种类型看起来是等价的,所以上面的代码无法编译:

../test.cpp:51:19: error: redefinition of ‘T f() [with T = long unsigned int]’
 template<> size_t f<size_t>(void) { return 2; }
                   ^
../test.cpp:50:26: note: ‘T f() [with T = long unsigned int]’ previously declared here
 template<> unsigned long f<unsigned long>(void) { return 1; }
                          ^
Run Code Online (Sandbox Code Playgroud)

根据我的想法,这个问题可以通过简单地禁用size_t函数定义来解决,因为任何试图调用的代码f<size_t>()都会自动解析f<unsigned long>().但是应该为定义size_t不同的平台启用该功能unsigned long.

我已经阅读了一些关于模板元编程和SFINAE的内容,我一直在玩这样的事情:

std::enable_if<(sizeof(size_t) > sizeof(unsigned long))>::type 
Run Code Online (Sandbox Code Playgroud)

但我不确定如何使用这样的片段来禁用全局函数定义,如果可能的话.

那么,有没有办法使用模板元编程来有条件地禁用全局函数定义?或者,更一般地说,我是在正确的轨道上,还是走错了路?

dav*_*igh 5

这在任何情况下都有效,但它有点单调乏味,并且不适合大量的专业化:

template<typename T
       , std::enable_if_t<!std::is_same<T, unsigned long>::value
                       && !std::is_same<T, size_t>::value>* = nullptr>
T f() { return 1; }

template<typename T
       , std::enable_if_t<std::is_same<T, unsigned long>::value>* = nullptr>
T f() { return 2; }

template<typename T
       , std::enable_if_t<std::is_same<T, size_t>::value
                      && !std::is_same<T, unsigned long>::value>* = nullptr>
T f() { return 3; }
Run Code Online (Sandbox Code Playgroud)

这个想法:不专门但是过载,只有在签名合适时才启用重载(同时禁用其他签名).

此外,为了使其更易于维护,应该将逻辑检查外包到另一个合适的类中.


演示:

int main()
{
    std::cout<<f<int>()<<std::endl;
    std::cout<<f<unsigned long>()<<std::endl;
    std::cout<<f<size_t>()<<std::endl;
    std::cout<<f<unsigned long long>()<<std::endl;
}
Run Code Online (Sandbox Code Playgroud)

它打印:

1
2
2
1
Run Code Online (Sandbox Code Playgroud)

所以它似乎size_t == unsigned long在coliru上.