开发者

Lack of orthogonality in templates between class and function

// InternalTemplate.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

template<class T>
struct LeftSide
{
 static void insert(T*& newLink, T*& parent)
 {
  parent->get开发者_运维知识库Left() = newLink;
  newLink->parent = newLink;
 }
};

template<class T>
struct Link
{
 T* parent_;
 T* left_;
 T* right_;
 T*& getParent()const
 {
  return parent_;
 }
 template<class Side>
 void plugIn(Link<T>*& newLink);


};

template<class T>
template<class Side>
void Link<T>::plugIn(Link<T>*& newLink)//<<-----why can't I type  
//void Link<T>::plugIn<Side>(Link<T>*& newLink)<---<Side> next to plugIn


{
 Side::insert(newLink,this);
}

int _tmain(int argc, _TCHAR* argv[])
{
 return 0;
}

I find it strange that I have to specify parameter for a class but cannot specify parameter for a function. Is there any reason why?


Function templates and class templates are complementary (I call them orthogonal, but you are free not to agree), and in template metaprogramming they actually serve orthogonal purposes.

Class templates allow you to pattern match on the template argument, ie. they provide partial specialization.

Function templates, to the contrary, don't allow partial specialization, but they allow template argument deduction, which means you don't have to write the template arguments explicitly (except for extra arguments, as in your example).

This, I think, explains the differences in syntax since they are different in what they can achieve. Moreover, function templates can have overloads, class templates cannot.

The way to combine both concepts is

1) to have helper class templates with static non template functions if you want partial specialization for function templates:

template <typename T>
struct doSomethingWithPointersHelper
{
    static void act(T x) { ... }
};

template <typename T>
struct doSomethingWithPointersHelper<T*>
{
    static void act(T* x) { ... }
};

// This acts as if we had a partial specialization
// for pointer types
template <typename T>
doSomethingWithPointers(T x)
{ return doSomethingWithPointersHelper<T>::act(x); }

There are other ways to achieve this in particular cases, but this approach always works.

2) To have helper template functions if you want to make use of argument deduction when constructing complex classes:

template <typename T, typename U>
struct MyComplexClass
{ ... };

template <typename T, typename U>
MyComplexClass<T, U> makeComplex(T t, U u)
{ return MyComplexClass<T, U>(t, u); }

in the standard library, you find make_pair, bind1st or mem_fun which make use of this technique.


$14/2 -

A template-declaration can appear only as a namespace scope or class scope declaration. In a function template declaration, the last component of the declarator-id shall be a template-name or operator-functionid (i.e., not a template-id). [ Note: in a class template declaration, if the class name is a simple-template-id, the declaration declares a class template partial specialization (14.5.5). —end note ]"

The standard forbids such a syntax explicitly. Refer this for more idea about template id / template name


You need to specialize on the Link struct in order to define it's template member function.

template<>
template<class Side>
void Link<int>::plugIn(Link<int>*& newLink)
{
 Side::insert(newLink,this);
}

Gotta be honest, this makes my brain explode a little.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜