2015-03-31 253 views
1

我想在我的一个项目中添加对icc的支持,但是当有两种以上的方法时,我有一些SFINAE的问题。这是问题的一个裸简单的例子:如何使用英特尔C++编译器(ICC)的三种方法使用SFINAE?

#include <iostream> 

template<std::size_t Selector> 
struct impl { 
    template<bool Enable = true, typename std::enable_if<Selector == 1 && Enable, int>::type = 0> 
    static void apply(){ 
     std::cout << "First selector" << std::endl; 
    } 

    template<bool Enable = true, typename std::enable_if<Selector == 2 && Enable, int>::type = 0> 
    static void apply(){ 
     std::cout << "Second selector" << std::endl; 
    } 

    template<bool Enable = true, typename std::enable_if<Selector == 3 && Enable, int>::type = 0> 
    static void apply(){ 
     std::cout << "Big selector" << std::endl; 
    } 
}; 

int main(){ 
    impl<1>::apply(); 
    impl<2>::apply(); 
    impl<3>::apply(); 

    return 0; 
} 

这种工作方式和g的魅力++和铛++,但无法与ICC编译:

test.cpp(16): error: invalid redeclaration of member function template "void impl<Selector>::apply() [with Selector=1UL]" (declared at line 11) 
     static void apply(){ 
       ^
      detected during instantiation of class "impl<Selector> [with Selector=1UL]" at line 22 

test.cpp(11): error: invalid redeclaration of member function template "void impl<Selector>::apply() [with Selector=3UL]" (declared at line 6) 
     static void apply(){ 
       ^
      detected during instantiation of class "impl<Selector> [with Selector=3UL]" at line 24 

compilation aborted for test.cpp (code 2) 

是否有此与ICC解决方法?我想避免更改太多的代码,我在我的项目的几个地方有这个问题。

我正在使用icc 16.0.2.164。

感谢

+0

显而易见的解决方法是部分专业化。即使这意味着将“应用”到“impl_base ”,并将“使用impl_base ”添加到“impl”本身。这完全避免了对SFINAE的需求。 – MSalters 2015-03-31 08:05:04

+0

你使用什么版本的ICC? – usr1234567 2015-03-31 08:15:44

+1

这是不合格的,无论如何不需要诊断。对于任何给定的'impl'的实例,对于至少两个“apply”中的至少两个,不能生成有效的特化。 – 2015-03-31 08:15:57

回答

1

对于这个问题表示,明确专门的成员函数的代码,如图@ Jarod42的答案,可能是最简单的。

当SFINAE根据类模板的参数创建类模板成员函数时,获取代码正确可能会非常棘手。 [temp.res]/P8:

如果可以为一个模板来生成没有有效的专门化,并且 模板没有实例化,是形成不良的模板,没有 诊断必需的。

诀窍是具有SFINAE表达依赖于成员函数模板的参数:

template<std::size_t Selector> 
struct impl { 
    template<std::size_t S = Selector, typename std::enable_if<S == 1, int>::type = 0> 
    static void apply(){ 
     std::cout << "First selector" << std::endl; 
    } 

    template<std::size_t S = Selector, typename std::enable_if<S == 2, int>::type = 0> 
    static void apply(){ 
     std::cout << "Second selector" << std::endl; 
    } 

    template<std::size_t S = Selector, typename std::enable_if<S == 3, int>::type = 0> 
    static void apply(){ 
     std::cout << "Big selector" << std::endl; 
    } 
}; 

注意,每个上述apply() S的具有一个有效的特化。

+0

它确实工作,谢谢,但为什么不只是简单地添加一个布尔模板参数?为什么它与gcc/clang一起工作? – 2015-03-31 08:48:36

+1

@BaptisteWicht因为在你的代码中,没有任何可能的方式来为'impl <2>'中的第一个'apply'生成一个有效的特化。无论bool参数的值如何,签名仍然无效。由于不需要诊断,因此编译器可以拒绝它,但不是必需的。 – 2015-03-31 08:54:57

2

专业化是一个解决方案:

template<std::size_t Selector> 
struct impl { 
    static void apply(); 
}; 

template<> 
void impl<1>::apply(){ 
    std::cout << "First selector" << std::endl; 
} 

template<> 
void impl<2>::apply(){ 
    std::cout << "Second selector" << std::endl; 
} 

template<> 
void impl<3>::apply(){ 
    std::cout << "Big selector" << std::endl; 
}