首页 > c++ > 如何在英特尔C ++编译器(ICC)的三种方法中使用SFINAE?

如何在英特尔C ++编译器(ICC)的三种方法中使用SFINAE? (How to use SFINAE on three methods with Intel C++ Compiler (ICC)?)

问题

我正在尝试在我的一个项目上添加对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 ++和clang ++的魅力,但无法用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。

谢谢

解决方法

对于问题中显示的代码,显式专门化成员函数,如@ 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()都有一个有效的专业化。

问题

I'm trying to add support for icc on one of my projects, but I have some issues with SFINAE, when there are more than two methods. Here is a bare simple example of the problem:

#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;
}

This works like a charm with g++ and clang++, but fails to compile with 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)

Is there a workaround for this with icc ? I'd like to avoid changing too much code, I have this problem in several places of my project.

I'm using icc 16.0.2.164.

Thanks

解决方法

For the code shown in the question, explicitly specializing the member function, as shown in @Jarod42's answer, is probably the simplest.

When SFINAE'ing a class template member function based on parameters of the class template, getting the code correct can be tricky. [temp.res]/p8:

If no valid specialization can be generated for a template, and that template is not instantiated, the template is ill-formed, no diagnostic required.

The trick is to have the SFINAE expression depend on parameters of the member function template:

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;
    }
};

Note that each of the above apply()s has one valid specialization.

相似信息