gpt4 book ai didi

c++ - 部分模板参数应用程序的部分模板特化不适用于 GCC 4.8.1

转载 作者:行者123 更新时间:2023-11-30 01:51:55 26 4
gpt4 key购买 nike

在我的基于策略的类的根部有一个容器适配器,它提供了一个用于在不同容器之间进行转换的接口(interface)。它由类型 T 和模板模板参数 Container 参数化。为了使其适用于标准容器,我需要部分应用它们的一些参数,例如分配器或数组大小。我是这样做的:

template< typename T >
struct vector_{
using policy = std::vector<T>; //default allocator
};

或者在给我带来麻烦的情况下:

 //data_adapter expects template template parameter that takes one type-argument,
//but sadly std::array is a template<typename, size_t>
//so we need to partially apply the size_t parameter
namespace array_detail{
template< size_t N >
struct array_impl{
template< typename T >
using array_default = std::array<T, N>;
}; //now we can write array_impl<32>::array_default which is template<typename T>
}

问题是我需要为 array_impl 的所有 N 个部分特化 data_adaptor 并且 GCC 4.8.1 在调用其构造函数时似乎不考虑我的特化。这是代码:

数据适配器.hpp:

//data_adapter.hpp
#ifndef __DATA_ADAPTER_HPP__
#define __DATA_ADAPTER_HPP__

#include <array>
#include <type_traits>

template <
typename T,
template< typename t >
class Container
> class data_adapter
: protected Container< T >
{
protected:
typedef Container<T> data_type;

public:
//constructor forwarding
using data_type::data_type;

//const iterator access for cross-container conversion copying
using data_type::cbegin;
using data_type::cend;

data_adapter() = default;

public:
~data_adapter() {}
};

//SFINAE helper to test whether T is an iterator or not

template<typename T, typename = void>
struct is_iterator
{
static constexpr bool value = false;
};

template<typename T>
struct is_iterator<T, typename std::enable_if<!std::is_same<typename std::iterator_traits<T>::value_type, void>::value>::type>
{
static constexpr bool value = true;
};

//data_adapter expects template template parameter that takes one type-argument,
//but sadly std::array is a template<typename, size_t>
//so we need to partially apply the size_t parameter
namespace array_detail{
template< size_t N >
struct array_impl{
template< typename T >
using array_default = std::array<T, N>;
}; //now we can write array_impl<32>::array_default which is template<typename T>
}

//partial specialization for array_impl<N>::array_default for any N???

template< typename T, size_t N >
class data_adapter< T, array_detail::array_impl<N>::template array_default >
: protected array_detail::array_impl<N>::template array_default<T>
{
protected:
typedef typename array_detail::array_impl<N>::template array_default<T> data_type;

public:
using data_type::data_type;

using data_type::cbegin;
using data_type::cend;

//why doesn't std::array implement this constructor?
//is it because it has static size and conversion from a dynamic container is dangerous?

template<
typename InputIt,
typename = typename
std::enable_if<is_iterator<InputIt>::value>::type
> data_adapter( InputIt begin, InputIt end )
: data_type() {
std::copy( begin, end, this->begin() );
}

public:
~data_adapter() {}
};

//still doesn't work with explicit instantiation
//template class data_adapter< int, array_detail::array_impl<32>::template array_default >;

#endif // __DATA_ADAPTER_HPP__

主要.cpp:

//main.cpp
#include <algorithm>
#include <ctime>
#include <cstdint>
#include <iostream>
#include <random>


#include "data_adapter.hpp"

int main()
{
std::mt19937 generator(time(NULL));
std::uniform_int_distribution<unsigned char> uniform_symbol( 0, 255 );
auto random_symbol =
[ &generator, &uniform_symbol ]( int ){
return uniform_symbol(generator);
};

std::vector< int > symbols(32);
std::transform( symbols.cbegin(), symbols.cend(), symbols.begin(), random_symbol );

data_adapter< int, array_detail::array_impl<32>::template array_default > adapter( symbols.cbegin(), symbols.cend() );

std::for_each( symbols.begin(), symbols.end(), []( int s ){ std::cout << s << " "; } );

return 0;
}

错误:

g++.exe -Wall -fexceptions  -std=c++11 -g  -Wall    -c C:\Users\windows\Desktop\data_test\main.cpp -o obj\Debug\main.o
C:\Users\windows\Desktop\data_test\main.cpp: In function 'int main()':
C:\Users\windows\Desktop\data_test\main.cpp:23:119: error: no matching function for call to 'data_adapter<int, array_detail::array_impl<32u>::array_default>::data_adapter(std::vector<int>::const_iterator, std::vector<int>::const_iterator)'
data_adapter< int, array_detail::array_impl<32>::template array_default > adapter( symbols.cbegin(), symbols.cend() );
^
C:\Users\windows\Desktop\data_test\main.cpp:23:119: note: candidates are:
In file included from C:\Users\windows\Desktop\data_test\main.cpp:9:0:
C:\Users\windows\Desktop\data_test\data_adapter.hpp:25:3: note: data_adapter<T, Container>::data_adapter() [with T = int; Container = array_detail::array_impl<32u>::array_default]
data_adapter() = default;
^
C:\Users\windows\Desktop\data_test\data_adapter.hpp:25:3: note: candidate expects 0 arguments, 2 provided
C:\Users\windows\Desktop\data_test\data_adapter.hpp:11:9: note: constexpr data_adapter<int, array_detail::array_impl<32u>::array_default>::data_adapter(const data_adapter<int, array_detail::array_impl<32u>::array_default>&)
> class data_adapter
^

显然没有考虑我在array_impl的部分特化中定义的构造函数,所以结论是main.cpp中的data_adaptor实例化了类的非特化版本。这不是 SFINAE 问题,因为编译器会提示 std::enable_if 中缺少::type。即使,如果我显式实例化专用版本,它仍然不起作用。我在这里做错了什么?


编辑:这是我认为等效的最小版本:

#include <iostream>
#include <array>

template<
typename T,
template < typename >
class Container
> struct Foo{
void test() const {
std::cout << "Unspecialized Foo" << std::endl;
}
};

template< size_t N >
struct array_{
template< typename T >
using policy = std::array<T, N>;
};

template<
typename T, size_t N
> struct Foo< T, array_<N>::template policy >{
void test() const {
std::cout << "Foo< T, array<" << N << ">::policy >" << std::endl;
}
};

int main()
{
Foo< int, array_<10>::template policy > foo;
foo.test();
return 0;
}

GCC 4.8.1 的结果:

Unspecialized Foo

为什么叫非特化版?


编辑 2:当我这样写时它似乎有效:

#include <iostream>
#include <array>

template<
typename container
> struct Foo{
void test() const {
std::cout << "Unspecialized Foo" << std::endl;
}
};

template<
typename T, size_t N
> struct Foo< std::array<T, N> >{
void test() const {
std::cout << "Foo< std::array< T, " << N << ">" << std::endl;
}
};

int main()
{
Foo< std::array<int, 10> > foo;
foo.test();
return 0;
}

在我看来像是 GCC 错误。

最佳答案

这不是编译器错误。 §14.5.5.1 [temp.class.spec.match]/p1-2 指定

When a class template is used in a context that requires an instantiation of the class, it is necessary to determine whether the instantiation is to be generated using the primary template or one of the partial specializations. This is done by matching the template arguments of the class template specialization with the template argument lists of the partial specializations.

  • If exactly one matching specialization is found, the instantiation is generated from that specialization.
  • If more than one matching specialization is found, the partial order rules (14.5.5.2) are used to determine whether one of the specializations is more specialized than the others. If none of the specializations is more specialized than all of the other matching specializations, then the use of the class template is ambiguous and the program is ill-formed.
  • If no matches are found, the instantiation is generated from the primary template.

A partial specialization matches a given actual template argument list if the template arguments of the partial specialization can be deduced from the actual template argument list (14.8.2).

这使用标准模板参数推导规则,以及 :: 左侧的任何内容(技术术语是 nested-name-specifier qualified-id) 是一个非推导上下文 (§14.8.2.5 [temp.deduct.type]/p5),这意味着编译器将无法推导 N;由于推导失败,部分特化不匹配,使用基本模板。

关于c++ - 部分模板参数应用程序的部分模板特化不适用于 GCC 4.8.1,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25483764/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com