std :: enable_if有条件地编译成员函数 [英] std::enable_if to conditionally compile a member function

查看:1997
本文介绍了std :: enable_if有条件地编译成员函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图得到一个简单的例子来理解如何使用 std :: enable_if 。在我阅读此答案后,我认为这不应该太难拿出一个简单的例子。我想使用 std :: enable_if 在两个成员函数之间进行选择,并只允许使用其中一个。



不幸的是,以下不编译gcc 4.7和经过几个小时和小时的尝试我问你们我的错误是什么。

  #include< utility> 
#include< iostream>

模板<类T>
class Y {

public:
template< typename = typename std :: enable_if< true> :: type>
T foo(){
return 10;
}
template< typename = typename std :: enable_if< false> :: type>
T foo(){
return 10;
}

};


int main(){
Y< double> y;

std :: cout<< y.foo()<< std :: endl;
}

gcc报告以下问题:

 %LANG = C make CXXFLAGS = -  std = c ++ 0xenable_if 
g ++ -std = c ++ 0x enable_if.cpp -o enable_if
enable_if.cpp:12:65:error:`type'in`struct std :: enable_if< false>'不命名类型
enable_if.cpp:13:15:error:`template< class T> template< class> T Y :: foo()'不能重载
enable_if.cpp:9:15:error:with`template< class T& template< class>为什么g ++没有为第二个成员函数删除错误的实例化?为什么?g ++为什么不删除第二个成员函数的错误实例化? ?根据标准, std :: enable_if< bool,T = void> :: type 仅当布尔模板参数为true时存在。但为什么g ++认为这不是SFINAE?我认为重载错误消息来自g ++不删除第二个成员函数,并认为这应该是一个重载的问题。

解决方案

SFINAE只有在参数中的替换引起模板参数使结构不合理时才有效。没有这样的替代。


我想到了,并试图使用 std :: is_same< T,int> :: value ! std :: is_same<


这是因为当类模板实例化(当你创建一个 Y< int> 类型的对象时会发生这种情况),它实例化它的所有成员声明(不一定是它们的定义/主体!其中还有它的成员模板。注意, T 是已知的,而!std :: is_same < T,int> :: value 产生false。因此,它将创建一个 Y< int> 类,其中包含

  Y int> {
public:
/ *从
实例化模板< typename = typename std :: enable_if<
std :: is_same< T,int> :: value> :: type>
T foo(){
return 10;
}
* /

template< typename = typename std :: enable_if< true> :: type>
int foo();

/ *实例化从

模板< typename = typename std :: enable_if<
! std :: is_same< T,int> :: value> :: type>
T foo(){
return 10;
}
* /

template< typename = typename std :: enable_if< false> :: type>
int foo();
};

std :: enable_if< false> :: type 访问一个不存在的类型,所以声明是不成立的。因此你的程序是无效的。



您需要使成员模板 enable_if 依赖于成员模板本身的参数。然后声明是有效的,因为整个类型仍然是依赖的。当你尝试调用其中之一时,它们的模板参数的参数扣除发生,并且SFINAE会按预期发生。请参阅这个问题和相应的答案如何做。


I am trying to get a simple example to work to understand how to use std::enable_if. After I read this answer, I thought it shouldn't be too hard to come up with a simple example. I want to use std::enable_if to choose between two member-functions and allow only one of them to be used.

Unfortunately, the following doesn't compile with gcc 4.7 and after hours and hours of trying I am asking you guys what my mistake is.

#include <utility>
#include <iostream>

template< class T >
class Y {

    public:
        template < typename = typename std::enable_if< true >::type >
        T foo() {
            return 10;
        }
        template < typename = typename std::enable_if< false >::type >
        T foo() {
            return 10;
        }

};


int main() {
    Y< double > y;

    std::cout << y.foo() << std::endl;
}

gcc reports the following problems:

% LANG=C make CXXFLAGS="-std=c++0x" enable_if
g++ -std=c++0x    enable_if.cpp   -o enable_if
enable_if.cpp:12:65: error: `type' in `struct std::enable_if<false>' does not name a type
enable_if.cpp:13:15: error: `template<class T> template<class> T Y::foo()' cannot be overloaded
enable_if.cpp:9:15: error: with `template<class T> template<class> T Y::foo()'

Why doesn't g++ delete the wrong instantiation for the second member function? According to the standard, std::enable_if< bool, T = void >::type only exists when the boolean template parameter is true. But why doesn't g++ consider this as SFINAE? I think that the overloading error message comes from the problem that g++ doesn't delete the second member function and believes that this should be an overload.

解决方案

SFINAE only works if substitution in argument deduction of a template argument makes the construct ill-formed. There is no such substitution.

I thought of that too and tried to use std::is_same< T, int >::value and ! std::is_same< T, int >::value which gives the same result.

That's because when the class template is instantiated (which happens when you create an object of type Y<int> among other cases), it instantiates all its member declarations (not necessarily their definitions/bodies!). Among them are also its member templates. Note that T is known then, and !std::is_same< T, int >::value yields false. So it will create a class Y<int> which contains

class Y<int> {
    public:
        /* instantiated from
        template < typename = typename std::enable_if< 
          std::is_same< T, int >::value >::type >
        T foo() {
            return 10;
        }
        */

        template < typename = typename std::enable_if< true >::type >
        int foo();

        /* instantiated from

        template < typename = typename std::enable_if< 
          ! std::is_same< T, int >::value >::type >
        T foo() {
            return 10;
        }
        */

        template < typename = typename std::enable_if< false >::type >
        int foo();
};

The std::enable_if<false>::type accesses a non-existing type, so that declaration is ill-formed. And thus your program is invalid.

You need to make the member templates' enable_if depend on a parameter of the member template itself. Then the declarations are valid, because the whole type is still dependent. When you try to call one of them, argument deduction for their template arguments happen and SFINAE happens as expected. See this question and the corresponding answer on how to do that.

这篇关于std :: enable_if有条件地编译成员函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆