繁体   English   中英

boost :: enable_if不在函数签名中

[英]boost::enable_if not in function signature

这只是关于样式的问题:我不喜欢C ++用于模板元编程的方式,该方式要求您使用返回类型或为SFINAE的技巧添加额外的哑元参数。 因此,我想到的想法是将SFINAE东西放在模板参数定义本身中,如下所示:

#include <iostream>
#include <boost/type_traits/is_array.hpp>
#include <boost/utility/enable_if.hpp>
using namespace std;

template <typename T, typename B=typename boost::enable_if< boost::is_array<T> >::type > void asd(){
    cout<<"This is for arrays"<<endl;
}

template <typename T, typename B=typename boost::disable_if< boost::is_array<T> >::type > void asd(){
    cout<<"This is for NON arrays"<<endl;
}

int main() {
    asd<int>();
    asd<int[]>();
}

这个例子使g ++抱怨:

../src/afg.cpp:10:97:错误:“模板无效asd()”的重新定义

SFINAE本身可以工作,因为例如如果我删除带有disable_if那个,则编译器错误是:

../src/afg.cpp:15:12:错误:没有匹配的函数可调用“ asd()”

这就是我想要的。

因此,有没有一种方法可以不在函数的“正常”签名(即返回类型+参数列表)中完成SFINAE?

编辑:这是最后我要在真实代码中尝试的方法:

#include <iostream>
#include <type_traits>
using namespace std;

template <typename T, typename enable_if< is_array<T>::value, int >::type =0 > void asd(){
    cout<<"This is for arrays"<<endl;
}

template <typename T, typename enable_if< !is_array<T>::value, int >::type =0 > void asd(){
    cout<<"This is for NON arrays"<<endl;
}

int main() {
    asd<int[]>();
    asd<int>();
}

我使用c ++ 0x而不是boost,因为只要我需要c ++ 0x来使用模板参数的默认值,我就没有理由使用boost了,boost是它的先驱。

好吧,我通常使用这些宏来使enable_if构造更整洁(它们甚至可以在大多数C ++ 03编译器中使用):

#define ERROR_PARENTHESIS_MUST_BE_PLACED_AROUND_THE_RETURN_TYPE(...) __VA_ARGS__>::type
#define FUNCTION_REQUIRES(...) typename boost::enable_if<boost::mpl::and_<__VA_ARGS__, boost::mpl::bool_<true> >, ERROR_PARENTHESIS_MUST_BE_PLACED_AROUND_THE_RETURN_TYPE
#define EXCLUDE(...) typename boost::mpl::not_<typename boost::mpl::or_<__VA_ARGS__, boost::mpl::bool_<false> >::type >::type

然后,您将如下定义函数:

template <typename T >
FUNCTION_REQUIRES(is_array<T>)
(void) asd(){
    cout<<"This is for arrays"<<endl;
}

template <typename T >
FUNCTION_REQUIRES(EXCLUDE(is_array<T>))
(void) asd(){
    cout<<"This is for NON arrays"<<endl;
}

唯一的是,您需要在返回类型两边加上括号。 如果您忘记了它们,则编译器会说“ ERROR_PARENTHESIS_MUST_BE_PLACED_AROUND_THE_RETURN_TYPE”是未定义的。

由于C ++ 11使其成为可能,所以我只在模板参数内使用enable_if (或相反的disable_if ),这是您的操作方式。 如果/当有多个重载时,我将使用默认的虚拟模板参数,这会使模板参数列表有所不同。 因此,重用您的示例将是:

template<
    typename T
    , typename B = typename boost::enable_if<
        boost::is_array<T>
    >::type
>
void asd() {
    cout << "This is for arrays" << endl;
}

template<
    typename T
    , typename B = typename boost::disable_if<
        boost::is_array<T>
    >::type
    , typename = void
>
void asd() {
    cout << "This is for arrays" << endl;
}

自从C ++ 03起不存在的不弄乱返回类型(在某些情况下,例如转换运算符不可用)的另一种替代方法是使用默认参数:

template<typename T>
void
foo(T t, typename std::enable_if<some_trait<T>::value>::type* = nullptr);

我不使用这种形式,因为出于一致性的原因(因为并非在所有情况下都不可行),我不喜欢将参数类型与返回类型一样“弄乱”。

默认模板参数不属于功能模板的签名。 但是模板参数的类型是。 因此,您可以执行以下操作并能够使其过载

template <
  typename T,
  typename boost::enable_if< 
    boost::is_array<T>, int 
  >::type = 0
> 
void asd() {
    cout<<"This is for arrays"<<endl;
}

template <
  typename T, 
  typename boost::disable_if< 
    boost::is_array<T>, int 
  >::type = 0 
>
void asd() {
    cout<<"This is for arrays"<<endl;
}

这可能不完全是您要的,但是好的旧模板专业化又如何呢?

template<typename T>
struct asd
{
    static void fgh()
    {
        std::cout << "not an array\n";
    }
};

template<typename T>
struct asd<T[]>
{
    static void fgh()
    {
        std::cout << "an array of unknown size\n";
    }
};

template<typename T, size_t N>
struct asd<T[N]>
{
    static void fgh()
    {
        std::cout << "an array of known size\n";
    }
};

int main()
{
    asd<int>::fgh();
    asd<int[]>::fgh();
    asd<int[42]>::fgh();
}

因此,有没有一种方法可以不在函数的“正常”签名(即返回类型+参数列表)中完成SFINAE?

好吧,有一种方法可以完全不使用SFINAE来获得相同的结果-重载:

#include <iostream>
#include <type_traits>

void asd_impl(std::true_type&&)
{
    std::cout << "This is for arrays\n";
}

void asd_impl(std::false_type&&)
{
    std::cout << "This is not for arrays\n";
}

template<typename T>
void asd()
{
    asd_impl(std::is_array<T>());
}

int main()
{
    asd<int>();
    asd<int[]>();
}

这种样式在IMO中更具可读性,并且在大量使用模板的库(例如Boost)中广泛使用。 精神,因为它倾向于更快地编译并且可以更好地与模板/ SFINAE支持不那么出色的编译器(例如VC ++和Sun Studio)一起工作。

在线演示。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM