【问题标题】:Unable to specialize a member function template with boost::enable_if in VS .NET 2008无法在 VS .NET 2008 中使用 boost::enable_if 专门化成员函数模板
【发布时间】:2014-04-01 15:03:22
【问题描述】:

我正在尝试为两种不同类型的类专门化一个成员函数模板,如下所示:

#include <iostream>
#include <boost/utility/enable_if.hpp>

struct Wibble
{
    static const bool CAN_WIBBLE = true;
};

struct Wobble
{
    static const bool CAN_WIBBLE = false;
};

struct Foo
{
    //template<typename T>   // Why isn't this declaration sufficient?
    //void doStuff();

    template<typename T>
    typename boost::enable_if_c<T::CAN_WIBBLE,void>::type
    doStuff();

    template<typename T>
    typename boost::enable_if_c<!T::CAN_WIBBLE,void>::type
    doStuff();  
};

template<typename T>
typename boost::enable_if_c<T::CAN_WIBBLE,void>::type
Foo::doStuff()
{
    std::cout << "wibble ..." << std::endl;
}

template<typename T>
typename boost::enable_if_c<!T::CAN_WIBBLE,void>::type
Foo::doStuff()
{
    std::cout << "I can't wibble ..." << std::endl;
}

int main()
{
    Foo f;
    f.doStuff<Wibble>();
    f.doStuff<Wobble>();
}

而 GCC 4.8.2 编译代码,VS .NET 2008 吐出错误消息:

error C2244: 'Foo::doStuff' : unable to match function definition to an existing declaration

        definition
        'boost::enable_if_c<!T::CAN_WIBBLE,void>::type Foo::doStuff(void)'
        existing declarations
        'boost::enable_if_c<!T::CAN_WIBBLE,void>::type Foo::doStuff(void)'
        'boost::enable_if_c<T::CAN_WIBBLE,void>::type Foo::doStuff(void)'

【问题讨论】:

  • 我会把它写下来,因为 MSVC++ 逻辑无法处理没有参数和明确指定参数的函数重载(我隐约记得远程相关案例也有一些问题)。当我想要参数推导时,我只会使用重载的函数模板; Jarod42 建议的标签调度是这里的首选方法。
  • gcc 是否在严格的 C++98 模式下编译它(-std=c++98)?在 C++11 和 MSVC++ 15.0 (MSVS 9.0 (2008)) 中规则有所放宽,而不是 C++11。
  • @Jan,我没有使用 C++11。如果方法是内联的,VS 也会编译它们。
  • 我知道您没有使用 C++11,但我不确定 gcc 是否接受默认模式下 C++98 中不允许的内容。这就是我询问严格模式的原因。
  • @Jan 代码使用严格的 C++98 标志在 gcc 4.8.2 中编译,-std=c++98

标签: c++ templates boost sfinae enable-if


【解决方案1】:

我建议使用标签调度:https://ideone.com/PA5PTg

struct Foo
{
    template<bool wibble>
    void _doStuff();

public:
    template<typename T>
    void doStuff()
    {
        _doStuff<T::CAN_WIBBLE>();
    }
};

template<>
void Foo::_doStuff<true>() { std::cout << "wibble ..." << std::endl; }

template<>
void Foo::_doStuff<false>() { std::cout << "I can't wibble ..." << std::endl; }

【讨论】:

    【解决方案2】:

    您不能部分专门化(成员)函数模板。故事结束。

    即使可以,您也应该拥有一个对 SFINAE 友好的主模板。在伪代码中:

    template<typename T, typename Enable> void doStuff();
    template<typename T> void doStuff<T, typename boost::enable_if_c<T::CAN_WIBBLE,void>::type>()
        { std::cout << "wibble ..." << std::endl; }
    template<typename T> void doStuff<T, typename boost::enable_if_c<!T::CAN_WIBBLE,void>::type>()
        { std::cout << "I can't wibble ..." << std::endl; }
    

    如果您准备好类模板(作为函子或只是定义非模板方法的类型...),您仍然可以使用此技术。

    根据经验,对于函数模板,重载解析提供了静态多态性,无需部分特化。见

    Herb Sutter 的作品

    【讨论】:

    • 这就是为什么注释掉的声明是不够的。但问题不是试图专门化功能模板。它试图定义两个不同的函数模板重载。
    • @JanHudec 我同意。 OP的代码根本不正确。但显然他正在寻找专业化的正确咒语(请参阅注释的主模板问题标题)。我的回答解释说没有正确的形式,它会是什么样子,为什么他不能让它工作,以及他能代替什么。
    • 据我所知,only 注释掉的部分不正确,但编写的代码实际上是正确(但缺少编译器)。
    • @JanHudec 我以为他已经更改了代码,直到编译器接受它。诚然,我没有注意 MSVC 错误消息(我从不注意,它们通常不是很丰富......)。干杯
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-03
    • 1970-01-01
    • 2021-06-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多