В основе моего класса, основанного на политике, лежит адаптер контейнера, который предоставляет интерфейс для преобразования между различными контейнерами. Он параметризуется типом 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>
}
Проблема в том, что мне нужно частично специализировать data_adaptor
для всех N из array_impl
, и GCC 4.8.1, похоже, не учитывает мою специализацию при вызове своего конструктора. Вот код:
data_adapter.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__
main.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, поэтому можно сделать вывод, что data_adaptor в main.cpp создал экземпляр неспециализированной версии класса. Это не проблема SFINAE, поскольку компилятор будет жаловаться на отсутствие :: type в std :: enable_if. Даже если я явно создаю экземпляр специализированной версии, она все равно не работает. Что я здесь делаю не так?
РЕДАКТИРОВАТЬ: Вот минимальная версия, которая, как мне кажется, эквивалентна:
#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.
std::array
, у которого есть целочисленный аргумент шаблона (но это решит проблему дляstd::vector
и т. Д., У всех которых есть дополнительные аргументы шаблона помимо типа значения). - person Seg Fault   schedule 25.08.2014::
, является невыведенным контекстом, что означает, что компилятор не может вывестиN
в вашей частичной специализации, и, следовательно, используется базовый шаблон. - person T.C.   schedule 25.08.2014