编译时模板参数计算

3

我正在尝试在编译时推导出两个模板参数中的较大值。这两个模板参数都是size_t类型。

我有一个模板类型SomeType,它以size_t作为模板参数。然后我有一个函数,它接受具有不同模板size_t的两个SomeType参数,我希望返回类型是一个SomeType,其模板size_t是两个输入size_t大小中的较大者。

template <size_t d> struct SomeType {...}

template<size_t d1, size_t d2>
SomeType<the_larger_of_d1_and_d2> Func(SomeType<d1> A, SomeType<d2> B)
{
    ...
}

可以的吗?

编译时是否已知参数? - Luchian Grigore
d1和d2已知,A和B未知。 - MuttonChops
一般来说,这是可能的。如果您使用较旧的 [tag:c++03] 标准,则必须实现一个类型选择器模板类,该类专门提供 class Aclass Btypedef,并将其针对您想要的条件进行 truefalse 的特化。 - πάντα ῥεῖ
4个回答

3
您可以直接计算类型,无需使用SFINAE技术:
template<size_t d1, size_t d2>
SomeType<(d1 > d2 ? d1 : d2)> Func(SomeType<d1> A, SomeType<d2> B)
{
    …
}

1
使用三元运算符 ?: 来从特定的布尔条件中进行选择是一个非常好的快捷方式! - πάντα ῥεῖ

1

@KonradRudolph的解决方案当然是正确的。但如果你想深入了解模板元编程,学习Boost.MPL会很快得到回报。它提供了一整套便利函数。例如,你的问题可以这样解决:

#include <iostream>
#include <boost/mpl/int.hpp>
#include <boost/mpl/max.hpp>

template<size_t d> 
struct SomeType
: 
    boost::mpl::int_<d> 
{};

template<size_t d1, size_t d2>
typename boost::mpl::max<SomeType<d1>, SomeType<d2> >::type
Func(SomeType<d1> A, SomeType<d2> B) 
{
    return typename boost::mpl::max<SomeType<d1>, SomeType<d2> >::type();
}

int main()
{
    SomeType<2> st2;
    SomeType<3> st3;
    boost::mpl::max<SomeType<2>, SomeType<3> >::type res = Func(st2, st3);
    std::cout << res.value;
}  

实时演示

一些注释:

  • SomeTypeboost::mpl::int_继承,使其具有typevalue,以及一些方便的标签。 这使得非常容易重用来自Boost.MPL的其他元函数
  • boost::mpl::max在后台执行相同的三元技巧。 在我看来,它更易读,并且如果您想要更改为另一个条件,则很容易这样做。
  • 使用Boost.MPL有一定的学习曲线,但链接文档中的教程应该可以帮助您入门。

0

如果您可以利用标准,您可以使用SFINAE标准支持:

template<size_t one, size_t two>
struct larger {
    static constexpr typename std::enable_if<(one > two), size_t>::type value() {
        return one;
    }

    static constexpr typename std::enable_if<(two >= one, size_t>::type value() {
        return two;
    }
};

那么

template<size_t d1, size_t d2>
SomeType<larger<d1, d2>::value()> Func(SomeType<d1> A, SomeType<d2> B)
{
    ...
}

1
嗯...如果你使用C++11,constexpr size_t larger(size_t a, size_t b) { return a < b : b : a; }似乎比那个元函数更简单。它可以通过将其变为模板来推广到除size_t之外的任何类型。尽可能避免使用SFINAE,这是一个不错的工具。 - David Rodríguez - dribeas

0

由于我不断地需要查看自己(旧代码)关于那个问题的内容,我决定制作一个GIT要点编译样例,允许(至少是我)快速访问一些“模板”代码(双关语),以便使用元编程条件类型选择功能进行操作(也适用于“旧”的标准):

选择器声明:

template<typename FalseType, typename TrueType, bool condition>
struct ConditionalTypeSelector {
    typedef void ResultType;
};

选择器专业化:

template<typename FalseType, typename TrueType>
struct ConditionalTypeSelector<FalseType,TrueType,false> {
    typedef FalseType ResultType;
};

template<typename FalseType, typename TrueType>
struct ConditionalTypeSelector<FalseType,TrueType,true> {
    typedef TrueType ResultType;
};

选定类型:

struct A {
    unsigned char member;
};

struct B {
    int member;
};

struct C {
    long long member;
};

测试:

#include <iostream>
#include <typeinfo>

using namespace std;

int main() {
    cout << typeid
                ( ConditionalTypeSelector
                      < A,B,(sizeof(A) > sizeof(B))>::ResultType
                ).name() << endl;
    cout << typeid
                ( ConditionalTypeSelector
                      <A,B,(sizeof(B) > sizeof(A)) >::ResultType
                ).name() << endl;
    cout << typeid
                ( ConditionalTypeSelector
                      < A,C,(sizeof(A) > sizeof(C))>::ResultType
                ).name() << endl;
    cout << typeid
                ( ConditionalTypeSelector
                      < C,B,true>::ResultType
                ).name() << endl;
    cout << typeid
                ( ConditionalTypeSelector
                      < C,A,false>::ResultType
                ).name() << endl;

    return 0;
}

将这个template更改为使用例如enum类型进行专门选择,或者应该在编译时检查的任何其他常量条件都很容易。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接