许多功能的相同模板

gia*_*uca 0 c++ templates preprocessor-directive

大家好(祝新年快乐!)

我正在用C++写一个(不是真的)简单的项目(我的第一个,来自普通的C).我想知道是否有办法简化具有相同模板模式的多个函数的定义.我想一个例子可以更好地解释这个问题.

上下文

假设我有一个"Set"类,它代表一个数字列表,定义为

template <class T>
class Set {
    static_assert(std::is_arithmetic<T>(), "Template argument must be an arithmetic type.");
    T *_address;
    ...
}
Run Code Online (Sandbox Code Playgroud)

所以,如果我有一个实例(比如说Set<double>)和一个数组U array[N],其中U是另一个算术类型并且N是一个整数,我希望能够执行一些操作,例如将数组的值赋给那些数组Set.因此我在类中创建了函数模板

template <class U, int N>
void assign(U (&s)[N]) {
    static_assert(std::is_arithmetic<U>(), "Template argument must be an arithmetic type.");
    errlog(E_BAD_ARRAY_SIZE, N == _size);
    idx_t i = 0;
    do {
        _address[i] = value[i];
    } while (++i < size);
}
Run Code Online (Sandbox Code Playgroud)

问题

至于我的测试,上面的代码完全正常.但是我发现真的很难看,因为我需要static_assert确保只将算术类型作为参数(参数U),我需要一种方法来确保数组大小(参数N).另外,我不与完成assign的功能,但我需要这么多的其他功能,如add,multiply,scalar_product等等,等等!

第一个解决方案

我当时想知道是否有更好的方式来编写这类课程.经过一些工作,我想出了一个预处理器指令:

#define arithmetic_v(_U_, _N_, _DECL_, ...)                                             \
        template <class U, idx_t N> _DECL_                                              \  
        {                                                                               \
            static_assert(std::is_arithmetic<U>(),"Rvalue is not an arithmetic type."); \
            errlog(E_BAD_ARRAY_SIZE, N == _size);                                       \
            __VA_ARGS__                                                                 \
        }
Run Code Online (Sandbox Code Playgroud)

从而将我的功能定义为

arithmetic_v(U, N,
             void assign(U (&value)[N]),
                 idx_t i = 0;
                 do {
                     _address[i] = value[i];
                 } while (++i < _size);
             )
Run Code Online (Sandbox Code Playgroud)

这在某种程度上更干净,但仍然不是最好的,因为我被迫丢失包裹函数体的括号(必须包含static_assertINSIDE函数本身,模板参数U在范围内).

这个问题

我发现的解决方案似乎工作得很好,代码比以前更具可读性,但是...我不能使用另一个构造,允许我构建一个更清晰的所有函数的定义,并仍然保留该static_assert块和关于数组大小的信息?对于我需要的每个函数重复一次模板代码真的很难...

谢谢

我只是想了解这种语言,因此我们非常感谢有关这一论点的任何其他信息.我尽可能多地搜索,但找不到任何东西(也许我想不出适当的关键词,要求谷歌找到相关的东西).在此先感谢您的帮助,祝大家新年快乐!

赞布罗塔

bol*_*lov 5

我强烈建议不要使用宏,除非没有办法解决它们(我想到的一个案例就是获取用于调试目的的行号).来自Google C++样式指南(http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Preprocessor_Macros):

宏意味着您看到的代码与编译器看到的代码不同.这可能会引入意外行为,尤其是因为宏具有全局范围.

我真的不明白为什么你考虑使用static_assert丑陋.还有另一种方法可以确保模板仅适用于使用SFINAE的某些类型.

template <class T, class Enable = void>
class X;

template <class T>
class X<T, typename std::enable_if<std::is_integral<T>::value>::type> {
};
Run Code Online (Sandbox Code Playgroud)

并且你可以使用一个using声明(没有双关语)来做更漂亮的事情:

template <class T>
using enable_if_integral_t = typename std::enable_if<std::is_integral<T>::value>::type;

template <class T, class Enable = void>
class X;

template <class T>
class X<T, enable_if_integral_t<T>> {
};
Run Code Online (Sandbox Code Playgroud)

现在

X<int> x; // ok, int is integral
X<float> y; // compile error
Run Code Online (Sandbox Code Playgroud)

SFINAE(替换失败不是错误)是C++中的一项功能,如果模板特化失败,则不会出现错误.

template <bool Cond, class T = void> struct enable_if.如果为true,T则启用类型作为成员类型.否则,没有定义.因此对于float类型是false并且不存在,所以模板专门化enable_if::typeCondenable_if::typeis_integralenable_if::type

template <class T>
class X<T, typename std::enable_if<std::is_integral<T>::value>::type>
Run Code Online (Sandbox Code Playgroud)

失败,但使用通用模板

template <class T, class Enable = void>
class X;
Run Code Online (Sandbox Code Playgroud)

声明但未定义.

这很有用,因为您可以拥有更多专业化,例如:

template <class T>
using enable_if_integral_t = typename std::enable_if<std::is_integral<T>::value>::type;

template <class T>
using enable_if_floating_t = typename std::enable_if<std::is_floating_point<T>::value>::type;


template <class T, class Enable = void>
class X;

template <class T>
class X<T, enable_if_integral_t<T>> {
};
template <class T>
class X<T, enable_if_floating_t<T>> {
};
Run Code Online (Sandbox Code Playgroud)

希望你发现这至少有趣.

新年快乐!

编辑

我应该在哪里放入<T, enable_if_integral_t<T>>函数定义?我只能用类模板完成这个...

对于函数,enable_if :: type可以是返回类型.例如,如果f返回int,您可以:

#include <type_traits>

template <class T>
typename std::enable_if<std::is_integral<T>::value, int>::type f(T a) {
    return 2 * a;
}

int main() {
    f(3); // OK
    f(3.4); // error
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

并与using:

#include <type_traits>

template <class T, class Return = void>
using enable_if_integral_t = typename std::enable_if<std::is_integral<T>::value, Return>::type;

template <class T>
enable_if_integral_t<T, int> f(T a) {
    return 2 * a;
}

int main() {

    f(3); // OK
    f(3.4); // Error
    return 0;
}
Run Code Online (Sandbox Code Playgroud)