2011-04-14 67 views
23

考虑以下类,内部结构Y被用作类型,例如。模板,以后:有条件的编译时包含/排除基于模板参数的代码?

template<int I> 
class X{ 
    template<class T1> 
    struct Y{}; 

    template<class T1, class T2> 
    struct Y{}; 
}; 

现在,这个例子显然不会编译,与错误的第二X<I>::Y已被定义或有太多的模板参数。
我想解决没有(额外)部分专业化,因为int I参数不是唯一的,它的位置可以在不同的部分专业化不同(我的实际结构看起来more like this,以上只是为了简单的问题),所以我想one class fits every I解决方案。


我的第一个想法是明显enable_if,但似乎无法在我身上,例如。我仍然得到同样的错误:

// assuming C++11 support, else use boost 
#include <type_traits> 

template<int I> 
class X{ 
    template<class T1, class = std::enable_if<I==1>::type> 
    struct Y{}; 

    template<class T1, class T2, class = std::enable_if<I==2>::type> 
    struct Y{}; 
}; 

所以,既然enable_if失败了,我希望有另一种方式来实现以下编译时检查:

template<int I> 
class X{ 
    __include_if(I == 1){ 
    template<class T1> 
    struct Y{}; 
    } 

    __include_if(I == 2){ 
    template<class T1, class T2> 
    struct Y{}; 
    } 
}; 

它只是是为了节省我很多的代码重复,但如果它在某种程度上可能,我会非常高兴。
编辑:可惜的是,我不能使用显而易见的:variadic模板,因为我使用的是Visual Studio 2010,所以只能使用支持的C++ 0x东西。 :/

+0

+1。有趣的问题。将在办公时间后尝试回答:D – Nawaz 2011-04-14 06:00:26

+0

我很高兴地等待着它。 :)我的思路是,它应该是可能的,因为编译器知道它需要知道的一切,以及编译时。 – Xeo 2011-04-14 06:09:56

+0

@ Xeo:你允许使用C++ 0x feautures吗? – Nawaz 2011-04-14 06:32:28

回答

8

有两个问题在这里:

  1. enable_if作品与部分专业化,不是主要的模板。
  2. 外部可见参数的数量由主模板确定,其中可能只有一个。

答案1.

正如你在聊天建议,模板链表可以模拟一个可变参数包。

template<int I> 
class X{ 
    template<class list, class = void> 
    struct Y; 

    template<class list> 
    struct Y< list, typename std::enable_if<I==1>::type > { 
     typedef typename list::type t1; 
    }; 

    template<class list> 
    struct Y< list, typename std::enable_if<I==2>::type > { 
     typedef typename list::type t1; 
     typedef typename list::next::type t2; 
    }; 
}; 

如果你结束了next::next::next垃圾,很容易写一元函数,或者使用升压MPL。


回答2.

不同,元数的模板可以类似地命名,但仍停留不同,如果他们被嵌套在SFINAE控制型内。

template<int I> 
class X{ 
    template<typename = void, typename = void> 
    struct Z; 

    template<typename v> 
    struct Z< v, typename std::enable_if<I==1>::type > { 
     template<class T1> 
     struct Y{}; 
    }; 

    template<typename v> 
    struct Z< v, typename std::enable_if<I==2>::type > { 
     template<class T1, class T2> 
     struct Y{}; 
    }; 
}; 

X<1>::Z<>::Y<int> a; 
X<2>::Z<>::Y< char, double > b; 
+0

先生您能否请您解释一下您的帖子“enable_if适用于部分专业化,而不是主要模板”。为什么不能像OP一样使用主模板?非常感谢:) – 2016-01-01 09:27:46

+1

@AngelusMortis推导部分特化模板参数(§14.5.5.1[temp.class.spec.match])。 'enable_if'在那里工作,因为替代失败不是错误(SFINAE)在扣除之内。主模板没有这种好处 - 替换失败是一个错误。 – Potatoswatter 2016-01-03 07:33:58

0

这种方法怎么样 - http://sergey-miryanov.blogspot.com/2009/03/template-class-overriding.html? (对不起,俄语)

+0

遗憾的是不适用,因为内部模板结构应该用作类型,例如在模板中。 :/ – Xeo 2011-04-14 06:15:31

+0

Btw,[这里是谷歌翻译的网站](http://translate.google.de/translate?js=n&prev=_t&hl=de&ie=UTF-8&layout=2&eotf=1&sl=ru&tl=en&u=http%3A %2F%2Fsergey-miryanov.blogspot.com%2F2009%2F03%2Ftemplate-class-overriding.html&act = url),这意味着您的意图很好。 – Xeo 2011-04-14 06:19:23

+0

第二个想法,也许这将与一些decltype欺骗。我回家后会试试。 :) – Xeo 2011-04-14 06:27:49

1

你能试试以下(这是不偏特):

template<int I> 
class X 
{ 
}; 

template<> 
class X<1> 
{ 
    template<class T1> 
    struct Y{}; 
}; 

template<> 
class X<2> 
{ 
    template<class T1, class T2> 
    struct Y{}; 
}; 

我如果答案是简单的怀疑!

编辑(模拟部分专业化): @Xeo,我能够编译下面的代码,似乎是fullfilling。

template<int I> 
struct X 
{ 
    struct Unused {}; // this mocking structure will never be used 

    template<class T1, class T2 = Unused> // if 2 params passed-->ok; else default='Unused' 
    struct Y{}; 

    template<class T1> 
    struct Y<T1, Unused>{}; // This is specialization of above, define it your way 
}; 

int main() 
{ 
    X<1>::Y<int> o1; // Y<T1 = int, T2 = Unused> called 
    X<2>::Y<int, float> o2; // Y<T1 = int, T2 = float> called 
} 

在这里,但是你可以< 1>,X < 2>交替使用X。但在你提到的更广泛的例子中,这是无关紧要的。如果你需要,你可以把支票I = 1I = 2

+0

这就是我的意思是“没有(额外)部分专业化”,因为'int I'不是唯一的模板参数,但还有其他的。我将Ideone与一个它看起来很像的小例子联系起来,为了简化问题,这个结构被忽略了。 – Xeo 2011-04-14 06:21:28

+0

你可以检查编辑后的版本吗?其实我已经把第二版模版作为主版本,第一版是第二版的专业版。希望能帮助到你! – iammilind 2011-04-14 11:43:29

3

在这里你去:

http://ideone.com/AdEfl

,代码:

#include <iostream> 

template <int I> 
struct Traits 
{ 
    struct inner{}; 
}; 

template <> 
struct Traits<1> 
{ 
    struct inner{ 
    template<class T1> 
    struct impl{ 
     impl() { std::cout << "impl<T1>" << std::endl; } 
    }; 
    }; 
}; 

template <> 
struct Traits<2> 
{ 
    struct inner{ 
    template<class T1, class T2> 
    struct impl{ 
     impl() { std::cout << "impl<T1, T2>" << std::endl; } 
    }; 
    }; 
}; 

template<class T> 
struct Test{}; 

template<class T, class K> 
struct Foo{}; 

template<int I> 
struct arg{}; 

template< 
    template<class, class> class T, 
    class P1, int I 
> 
struct Test< T<P1, arg<I> > >{ 
    typedef typename Traits<I>::inner inner;  
}; 

template< 
    template<class, class> class T, 
    class P2, int I 
> 
struct Test< T<arg<I>, P2 > >{ 
    typedef typename Traits<I>::inner inner;  
}; 

// and a bunch of other partial specializations 

int main(){ 

    typename Test<Foo<int, arg<1> > >::inner::impl<int> b; 
    typename Test<Foo<int, arg<2> > >::inner::impl<int, double> c; 
} 

说明:基本上它是一个局部的专业化理念的延伸,不过不同的是,而不是专业内Test,委托给一个特定的类,可以专门在I单独。这样,您只需要为每个I一次定义inner的版本。然后Test的多个专业化可以重复使用。 inner持有人用于使Test类中的typedef更易于处理。

编辑:这是显示,如果你在错误的多项模板参数传递会发生什么测试用例:http://ideone.com/QzgNP

+0

我发布了相同的简化代码,但提问者说模板不会像'template '那么简单。 – iammilind 2011-04-14 11:20:07

+0

@iammilind,我说这是一个扩展,代码略有不同,在上文中,'I'的特化被委派给'Traits'类,而'Test'类使用它,在你的回答中,你是谈论专门针对每个“I”的“测试”(或“X”) - OP不愿意这么做。 – Nim 2011-04-14 11:35:29

+0

你是对的。我很抱歉,我错过了。感谢您的支持。 – iammilind 2011-04-14 14:19:50

0

您可以使用元函数(这里:内联boost::mpl::if_c,但可以是任意复杂的)到选择你想要的。你需要一些脚手架能够使用构造函数,虽然:

template <int I> 
class X { 
    template <typename T1> 
    class YforIeq1 { /* meat of the class */ }; 
    template <typename T1, typename T2> 
    class YforIeq2 { /* meat of the class */ }; 
public: 
    template <typename T1, typename T2=boost::none_t/*e.g.*/> 
    struct Y : boost::mpl::if_c<I==1,YforIeq1<T1>,YforIeq2<T1,T2> >::type { 
     typedef typename mpl::if_c<I==1,YforIeq1<T1>,YforIeq2<T1,T2> >::type YBase; 
     /* ctor forwarding: C++0x */ 
     using YBase::YBase; 
     /* ctor forwarding: C++03 (runs into perfect fwd'ing problem)*/ 
     Y() : YBase() {} 
     template <typename A1> 
     Y(const A1&a1) : YBase(a1) {} 
     template <typename A1, typename A2> 
     Y(const A1&a1, const A2&a2) : YBase(a1,a2) {} 
     // ... 
    }; 
}; 

如果有既YforIeqň问题被实例化每一个X,那么你可以沿着尝试包裹他们作为一个无参元函数(东西mpl::apply的方式)和使用mpl::eval_if_c