9

我看到了以下 C++11 的 enable_if 示例:

struct is_64_bit
{
    static const bool value = sizeof(void*) == 8;
};

enable_if<is_64_bit::value, void>::type
my_memcpy(void* target, const void* source, size_t n)
{
    cout << "64 bit memcpy" << endl;
}

enable_if<!is_64_bit::value, void>::type
my_memcpy(void* target, const void* source, size_t n)
{
    cout << "32 bit memcpy" << endl;
}

据我了解,根据系统架构,“my_memcpy”功能可用于 32 位或 64 位版本。但我在编译时收到以下错误:

error: ‘type’ in ‘struct std::enable_if<false, void>’ does not name a type

我有点困惑,因为我认为应该只有 32 版本可用(我使用的是 Linux Fedora 32 位)。

也许这个例子有问题?还是我错过了什么?

谢谢。

4

3 回答 3

12

std::enable_if通过替换失败不是错误(SFINAE) 的原则来工作,它指出当在实例化函数模板时发生某些类型的错误时,程序会继续使用该函数模板进行编译,而不参与重载决议。

要让 SFINAE 发挥作用,(a) 它必须在函数(或方法)模板上使用,并且 (b) 它必须依赖于模板参数。你的程序在这两个方面都失败了。

要使enable_if依赖模板参数,最简单的方法是添加一个默认参数:

template<typename T = void> typename enable_if<is_64_bit::value, T>::type
my_memcpy(void* target, const void* source, size_t n)

但是,这通常不是一个明智的使用enable_if; 因为它依赖于拦截编译错误,所以它往往很昂贵。在您的情况下,模板专业化将是一个更好的主意:

#include <iostream>

template<int = sizeof(void *)> void my_memcpy(void* target, const void* source, size_t n);

template<> void my_memcpy<8>(void* target, const void* source, size_t n) {
    std::cout << "64 bit memcpy" << std::endl;
}

template<> void my_memcpy<4>(void* target, const void* source, size_t n) {
    std::cout << "32 bit memcpy" << std::endl;
}
于 2012-09-27T16:24:17.507 回答
10

该模板template< bool B, class T = void > struct enable_if是专门的,因此它仅typedef type在条件 B 为时才具有 a true

你的编译器是正确的。typein没有 typedef struct std::enable_if<false, void>。中只有一个 typedef struct std::enable_if<true, void>

更多信息请看这里

因此,要解决您的问题,您需要确保enable_ifwhich 具有评估为false永远不会被编译的 B 。您可以在SFINAE的帮助下通过制作my_memcpy函数模板来实现这一点。编译器在编译 B 求值为 的函数模板失败时不会报告错误,false并将成功编译和使用 B 求值为 的函数true

#include <iostream>
#include <type_traits>

using namespace std;


struct is_64_bit
{
   static const bool value = sizeof(void*) == 8;
};

template<typename T>
typename enable_if<is_64_bit::value, T>::type
my_memcpy(T* target, const T* source, size_t n)
{
  cout << "64 bit memcpy" << endl;
}

template<typename T>
typename enable_if<!is_64_bit::value, T>::type
my_memcpy(T* target, const T* source, size_t n)
{
  cout << "32 bit memcpy" << endl;
}
于 2012-09-27T15:53:22.490 回答
5

SFINAE 用于模板。您需要的是使用模板,正如提到的其他答案,或者只是有一个编译时分支,IMO 是更合适的解决方案(而不是引入不必要的模板):

struct is_64_bit :
    std::integral_constant<bool, sizeof(void*) == 8>
{};

namespace detail
{
    void my_memcpy(void* target, const void* source, std::size_t n, std::true_type)
    {
        std::cout << "64 bit memcpy" << std::endl;
    }


    void my_memcpy(void* target, const void* source, std::size_t n, std::false_type)
    {
        std::cout << "32 bit memcpy" << std::endl;
    }
}

void my_memcpy(void* target, const void* source, std::size_t n)
{
    my_memcpy(target, source, n, is_64_bit());
}
于 2012-09-27T16:26:41.847 回答