如何在C ++中制作条件typedef


89

我正在尝试做这样的事情:

#include <iostream>
#include <random>

typedef int Integer;

#if sizeof(Integer) <= 4
    typedef std::mt19937     Engine;
#else
    typedef std::mt19937_64  Engine;
#endif

int main()
{
    std::cout << sizeof(Integer) << std::endl;
    return 0;
}

但是我得到这个错误:

error: missing binary operator before token "("

我该如何正确地设置条件typedef?


25
预处理器对sizeof或其他C ++构造一无所知。它当然不知道您使用自己创建的东西typedef,因为它甚至还没有被解析。
Lightness Races in Orbit

2
您可以使用enable_ifconditional有条件地定义typedef,但不能为此使用预处理器。
Bartek Banachewicz

1
@LightnessRacesinOrbit:预处理和编译集成在GCC中,因此不仅可以确定软件处理代码不了解用户创建的类型定义,而且对于GCC来说是错误的。sizeof无法在预处理器条件下工作的原因是因为以这种方式定义了语言,而不是因为实现的工作方式。
Eric Postpischil 2013年

1
@LightnessRacesinOrbit:翻译阶段定义语法和语义,而不是处理顺序。根据C ++ 2011(N3092)2.2 [lex.phases]注释11,“实现必须表现得好像这些单独的阶段一样,尽管实际上不同的阶段可能会折叠在一起。” 我对GCC的观点很重要,因为它表明您认为这是实现的工作方式是错误的。换句话说,您的评论声称特定的实现方法可以防止这种情况。但是不是阻止这种情况的实现(我们可以做到);这是语言定义。
Eric Postpischil 2013年

1
@Eric:我并不是要声称任何有关实现的内容。我当然没有提到任何一个。我的评论陈述了一种行为,就像您一样,该行为也应遵守假设规则。我不认为我们实际上在这里有任何分歧-您的语言律师也可能直接来自镜像。:)
赛将于

Answers:


139

使用std::conditionalC ++ 11中的元函数。

#include <type_traits>  //include this

typedef std::conditional<sizeof(int) <= 4,
                         std::mt19937,
                         std::mt19937_64>::type Engine;

请注意,如果您使用的类型sizeof是模板参数,例如T,则必须使用typename

typedef typename std::conditional<sizeof(T) <= 4, // T is template parameter
                                  std::mt19937,
                                  std::mt19937_64>::type Engine;

或使Engine依赖于T

template<typename T>
using Engine = typename std::conditional<sizeof(T) <= 4, 
                                         std::mt19937,
                                         std::mt19937_64>::type;

这很灵活,因为现在您可以将其用作:

Engine<int>  engine1;
Engine<long> engine2;
Engine<T>    engine3; // where T could be template parameter!

4
+1次要nitpick:sizeof(int) <= 4由于在64位Windows计算机上,GCC(MinGW)x64编译器提供了检查功能,因此检查可能不是一种可移植的方法sizeof(int) = sizeof(long) = 4。更好的方法是sizeof(void*) <= 4
legends2k 2013年

@ legends2k:你的意思是Engine<void*> engine4;?;-)
Nawaz 2013年

2
@Nawaz:当然不是:)我的意思是std::conditional<sizeof(void*) <= 4, std::mt19937, std::mt19937_64>在第一个代码段中。
legends2k

1
@ legends2k:如果我为您提供了,您为什么要使用它Engine<void*>?:P
Nawaz

@Nawaz:哈哈...是的。但是,我认为可能OP应该知道的陷阱的基础上的大小检测架构int:)
legends2k

35

使用std::conditional您可以这样做:

using Engine = std::conditional<sizeof(int) <= 4, 
                               std::mt19937, 
                               std::mt19937_64
                               >::type;

如果要执行typedef,您也可以这样做。

typedef std::conditional<sizeof(int) <= 4, 
                         std::mt19937, 
                         std::mt19937_64
                         >::type Engine

有没有必要typename在这里
gx_

@gx_是的,过去使用模板而不是具体类型来放置它。
拉普兹

1
@LightnessRacesinOrbit好吧,我修复了一下。
拉普兹

5

如果您没有可用的C ++ 11(尽管您打算使用它,则看起来可以使用std::mt19937),则可以使用Boost元编程库(MPL)在没有C ++ 11支持的情况下实现相同的功能。这是一个可编译的示例:

#include <boost/mpl/if.hpp>
#include <iostream>
#include <typeinfo>

namespace mpl = boost::mpl;

struct foo { };
struct bar { };

int main()
{
    typedef mpl::if_c<sizeof(int) <= 4, foo, bar>::type Engine;

    Engine a;
    std::cout << typeid(a).name() << std::endl;
}

这会foo在我的系统上打印出乱码的名称,因为int这里是4字节。


1
您为什么不使用它if_c呢?编写(和理解)必须更容易:mpl::if_c<sizeof(int)<=4, foo, bar>::type。是不是
纳瓦兹

1
@Nawaz:确实,这在许多方面都更好。我已经忘记了mpl::if_c。我更新了示例,改为使用该方法。
杰森R
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.