简体   繁体   English

编译时的模板参数计算

[英]Template argument calculation at compile time

I'm trying to deduce the greater of two template arguments at compile time. 我试图在编译时推断出两个模板参数中较大的一个。 Both template arguments are of type size_t. 两个模板参数的类型都是size_t。

I have a templated type, SomeType, which takes a size_t as it's template argument. 我有一个模板类型SomeType,它接受size_t作为模板参数。 I then have a function that takes two SomeType parameters with different template size_t's and i want the return type to be a SomeType with its templated size_t to be the greater of the two input size_t sizes. 然后我有一个函数,它接受两个具有不同模板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)
{
    ...
}

Is this possible? 这可能吗?

You can compute the type directly, no need for SFINAE: 您可以直接计算类型,不需要SFINAE:

template<size_t d1, size_t d2>
SomeType<(d1 > d2 ? d1 : d2)> Func(SomeType<d1> A, SomeType<d2> B)
{
    …
}

The solution by @KonradRudolph is correct of course. @KonradRudolph的解决方案当然是正确的。 But if you want to delve further in to template metaprogramming, it would pay-off very quickly to learn Boost.MPL . 但是如果你想深入研究模板元编程,那么学习Boost.MPL会很快得到回报。 It provides a whole battery of convenience functions. 它提供了一整套便利功能。 Eg your question can be solved like 例如,您的问题可以解决

#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;
}  

Live Example . 实例

Some notes: 一些说明:

  • letting SomeType inherit from boost::mpl::int_ endows it with a type and value , as well as some convenient tags. SomeType继承自boost::mpl::int_赋予它一个typevalue ,以及一些方便的标签。 This makes it very easy to re-use other metafunctions from Boost.MPL 这使得重用Boost.MPL中的其他元函数变得非常容易
  • the boost::mpl::max does the same ternary trick behind the scenes. boost::mpl::max在幕后执行相同的三元技巧。 It is more readible IMO, and if you ever want to change to another condition it's easy to do so. 它更容易被IMO读取,如果你想改变到另一个条件,那么这很容易。
  • there is a bit of a learning curve for Boost.MPL, but the tutorial at the linked documentation should get you started. Boost.MPL有一点学习曲线,但链接文档中的教程应该可以帮助您入门。

If you can make use of the standard, you can use SFINAE standard support: 如果您可以使用标准,则可以使用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;
    }
};

Then 然后

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

As I'm constantly have to look up myself (my older code) about that question again and again, I've decided to make a GIT gist , and compilation sample that allows (at least me) to quickly access some 'template' code (pun intended), to play with the meta-programmed conditional type selection stuff (also working for the 'old' standard): 由于我经常不得不一次又一次地查询自己(我的旧代码)关于这个问题,我决定制作一个GIT要点 ,以及允许(至少我)快速访问某些“模板”代码的编译示例 (双关语),使用元编程的条件类型选择内容(也适用于'旧' 标准):

Selector declaration: 选择器声明:

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

Selector specialization(s): 选择器专业化:

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;
};

Selected types: 选定类型:

struct A {
    unsigned char member;
};

struct B {
    int member;
};

struct C {
    long long member;
};

Testing: 测试:

#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;
}

It's pretty easy to change this template to use eg an enum type for specialized selections, or whatever else constant condition known at compile time should be checked. 可以很容易地将此template更改为使用例如用于专门选择的enum类型,或者应该检查编译时已知的任何其他常量条件。

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

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