类似于C ++模板参数的函数签名式expression式
我在看Don Clugston的FastDelegate迷你库,注意到一个奇怪的语法窍门,结构如下:
TemplateClass< void( int, int ) > Object;
它几乎看起来好像一个函数签名被用作模板实例声明的参数。
这种技术(其在FastDelegate中的存在显然是由于一个Jody Hagins)被用来简化具有半任意数量的模板参数的模板实例的声明。
就机智而言,它允许这样的事情如下所示:
// A template with one parameter template<typename _T1> struct Object1 { _T1 m_member1; }; // A template with two parameters template<typename _T1, typename _T2> struct Object2 { _T1 m_member1; _T2 m_member2; }; // A forward declaration template<typename _Signature> struct Object; // Some derived types using "function signature"-style template parameters template<typename _Dummy, typename _T1> struct Object<_Dummy(_T1)> : public Object1<_T1> {}; template<typename _Dummy, typename _T1, typename _T2> struct Object<_Dummy(_T1, _T2)> : public Object2<_T1, _T2> {}; // A. "Vanilla" object declarations Object1<int> IntObjectA; Object2<int, char> IntCharObjectA; // B. Nifty, but equivalent, object declarations typedef void UnusedType; Object< UnusedType(int) > IntObjectB; Object< UnusedType(int, char) > IntCharObjectB; // C. Even niftier, and still equivalent, object declarations #define DeclareObject( ... ) Object< UnusedType( __VA_ARGS__ ) > DeclareObject( int ) IntObjectC; DeclareObject( int, char ) IntCharObjectC;
尽pipe真的有点ha,,但我觉得这种可变的模板参数的欺骗性仿真很令人兴奋。
这个技巧的真正好处在于,我可以将“Type1(Type2,Type3)”这样的文本结构作为parameter passing给模板。 所以这里是我的问题:编译器如何解释这个结构? 这是一个函数签名? 或者,它只是一个带括号的文本模式吗? 如果前者,那么这是否意味着就模板处理器而言,任意函数签名都是有效的types?
后续的问题是,因为上面的代码示例是有效的代码,为什么C ++标准不允许你做下面的事情,而不是编译?
template<typename _T1> struct Object { _T1 m_member1; }; // Note the class identifier is also "Object" template<typename _T1, typename _T2> struct Object { _T1 m_member1; _T2 m_member2; }; Object<int> IntObject; Object<int, char> IntCharObject;
关于你的第一个问题 – 有关int(char, float)
的types – 这是一个有效的C ++types,是一个函数的types,它接受一个char
和一个float
并返回一个int
。 请注意,这是实际函数的types,而不是函数指针,它将是一个int (*) (char, float)
。 任何函数的实际types都是这种不寻常的types。 例如,types
void DoSomething() { /* ... */ }
是void ()
。
这在常规编程中不会出现的原因是,在大多数情况下,您不能声明这种types的variables。 例如,这个代码是非法的:
void MyFunction() { void function() = DoSomething; // Error! }
但是,您真正看到使用函数types的一种情况是用于传递函数指针:
void MyFunction(void FunctionArgument()) { /* ... */ }
看到这种types的函数写入函数指针是比较常见的,但是接受函数本身是完全正确的。 它在幕后被铸造。
至于你的第二个问题,为什么用不同的参数编写相同的模板是不合法的,我不知道规范中完全禁止它的措辞,但是这与事实有关,声明一个类模板,你不能改变参数的数量。 然而,你可以提供一个局部特殊化的模板,它具有不同数量的参数,当然,部分特化只针对原始数量的参数。 例如:
template <typename T> class Function; template <typename Arg, typename Ret> class Function<Ret (Arg)> { /* ... */ };
这里, Function
总是需要一个参数。 模板专门化有两个参数,但专业化仍然只有一个types(具体来说, Ret (Arg)
)。
int* int_pointer; // int_pointer has type "int*" int& int_reference; // int_reference has type "int&" int int_value; // int_value has type "int" void (*function_pointer)(int, int); // function_pointer has type // "void (*)(int, int)" void (&function_reference)(int, int); // function_reference has type // "void (&)(int ,int)" void function(int, int); // function has type // "void(int, int)" template<> struct Object1<void(int, int)> { void m_member1(int, int); // wait, what?? not a value you can initialize. };