【问题标题】:Using SFINAE and void_t to determine type of elements inside a container使用 SFINAE 和 void_t 确定容器内元素的类型
【发布时间】:2019-08-03 02:11:04
【问题描述】:

在下面的代码中,我试图通过检查容器 C 是否具有成员 value_type 来确定容器内元素的类型。如果为真,我将类型设置为“value_type”。然而,即使一个类型没有成员 value_type 并且不是容器,当传递时,编译器似乎将 HasMemberT_value_type 的第二个参数设置为 True,即使它给出了错误。

template<typename...>
using void_t = void;

template<typename T, typename = void_t<>>
struct HasMemberT_value_type : std::false_type
{
};

template<typename T>
struct HasMemberT_value_type<T, void_t<typename T::value_type>> : std::true_type
{
};

template<typename T, bool = HasMemberT_value_type<T>::value>
struct ElementTypeT
{
    using Type = typename T::value_type;
};

template<typename T>
struct ElementTypeT<T, false>
{
};

template<typename T>
using ElementType = typename ElementTypeT<T>::Type;

template<typename T>
void printType(T const& c)
{
    std::cout << "Container of " << typeid(ElementType<T>).name() << " elements.\n";
}

int main()
{                                           
    std::array<char, 5> arr;
    char classic[] = {'a', 'b', 'c', 'd'};
                                            //GNU Compiler:
    printType<arr>();                       //Container of c elements.
    printType<classic>();                   //ERROR : "In instantiation of ‘struct ElementTypeT<char [4], true>’: ... error: ‘char [4]’ is not a
                                            //         class, struct, or union type
                                            //         using Type = typename T::value_type;"

}

In instantiation of ‘struct ElementTypeT&lt;char [4], true&gt;

为什么设置为真?

谢谢。

【问题讨论】:

  • ElementType 无条件使用ElementTypeT&lt;T&gt;::Type,您必须确定在传递非容器时应该是什么类型。例如对于printType&lt;classic&gt;();,应该打印什么?
  • classic 被传递给它时,printType 应该做什么?
  • 我希望它打印“Char”。我可以在部分专业化的 ElementTypeT 中写 using Type = T; 以便选择 char 吗?或者它会失败 SFINAE 技术?

标签: c++ templates sfinae void-t


【解决方案1】:

printType&lt;arr&gt;()printType&lt;classic&gt;() 不会编译。应该是printType(arr)printType(classic)

另一个问题是ElementTypeT&lt;T, true&gt; 有一个Type 成员,但ElementTypeT&lt;T, false&gt; 没有。因此,当您执行 using ElementType = typename ElementTypeT&lt;T&gt;::Type 并在执行 printType(classic) 时访问它时,它将失败。

要解决这个问题,请修改特化以便可以推导出数组:

template<typename T, std::size_t I>
struct ElementTypeT<T[I], false>
{
    using Type=T;
};

不确定为什么 ElementTypeT&lt;char [4], true&gt; 在您的代码中实例化。 When I ran it 它为我出现了false

下面是使用函数重载和 SFINAE 的更简单方法:

template<class T>
typename std::decay_t<T>::value_type get_value_type( T&& );

template<class R, std::size_t I>
R get_value_type( R(&)[I] );

template<class T>
void printType(T const& c) {
    std::cout << "Container of " << typeid(get_value_type(c)).name() << " elements.\n";
}

【讨论】:

  • 非常感谢。我的编译器一定有问题,因为我使用 -std=c++11 而你用 c++17 编译(我的 linux 没有更新的 gnu gcc 版本)..
  • 顺便说一句,你的答案(修改我的专业化),看来我需要完全使用部分专业化,因为我仍然遇到与上述相同的错误并且编译器没有检测到修改后部分专业化的更好匹配...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-01
相关资源
最近更新 更多