【问题标题】:How to use SFINAE on three methods with Intel C++ Compiler (ICC)?如何通过英特尔 C++ 编译器 (ICC) 在三种方法上使用 SFINAE?
【发布时间】:2015-03-31 08:00:34
【问题描述】:

我正在尝试在我的一个项目中添加对 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。

谢谢

【问题讨论】:

  • 显而易见的解决方法是部分专业化。即使这意味着将apply 移动到impl_base&lt;Selector&gt;,并将using impl_base&lt;Selector&gt; 添加到impl 本身。这完全回避了对 SFINAE 的需求。
  • 您使用的是哪个版本的 ICC?
  • 这是格式错误的,无论如何都不需要诊断。对于impl 的任何给定实例化,三个applys 中的至少两个都不能生成有效的特化。
  • 你想要完成什么?
  • 我使用的是 icc 16.0.2.164。我只是想根据父类的类型参数之一选择一个函数。 @T.C.你能发展吗?就我而言,该类中还有其他模板参数,并且我在项目中的几个地方都遇到了这个问题,我想避免更改太多代码。

标签: c++ templates c++11 icc


【解决方案1】:

专业化是一种解决方案:

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

【讨论】:

    【解决方案2】:

    对于问题中显示的代码,显式特化成员函数,如@Jarod42 的答案所示,可能是最简单的。

    当 SFINAE 基于类模板的参数生成类模板成员函数时,正确获取代码可能会很棘手。 [温度.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 都有一个有效的特化。

    【讨论】:

    • 它确实有效,谢谢,但为什么它不能简单地添加一个 bool 模板参数?为什么它可以与 gcc/clang 一起使用?
    • @BaptisteWicht 因为在您的代码中,没有办法为impl&lt;2&gt; 中的第一个apply 生成有效的特化。无论 bool 参数的值如何,签名仍然无效。由于不需要诊断,因此允许但不要求编译器拒绝它。
    猜你喜欢
    • 2013-11-11
    • 2014-02-03
    • 2016-03-22
    • 2021-01-31
    • 2015-09-14
    • 1970-01-01
    • 2011-12-14
    • 2013-06-06
    • 1970-01-01
    相关资源
    最近更新 更多