Каким образом я не могу инстанцировать объекта типа Foo с вышеупомянутым конструктором?
У меня есть класс Панель, которая использует внутреннее определение типа (как обходное решение для "шаблонных определений типов"), и намеревайтесь использовать ее в конструкторе как ниже (СЛУЧАЙ 1). Однако я, кажется, не заставляю это компилировать. Этот легальный C++? СЛУЧАЙ 2, кажется, предполагает, что проблема связана с определением типа в Панели.
Как может я определять конструктора, который примет станд.:: векторы объектов с типом в Панели?
#include <vector>
#include <iostream>
#include <utility>
template <typename T>
struct Bar
{
typedef std::pair<T, T> type; // or anything else that uses T
};
struct Foo
{
Foo() {}
// CASE 1: doesn't compile
template <typename T> explicit Foo( const std::vector<typename Bar<T>::type>& data )
{
std::cout << "Hello\n";
}
//// CASE 2: compiles, but it's not what I want
//template <typename T> explicit Foo( const std::vector<Bar<T> >& data )
//{
// std::cout << "Hello\n";
//}
};
int main()
{
std::vector<Bar<int>::type> v; // for CASE 1
//std::vector<Bar<int> > v; // for CASE 2
Foo f( v );
return 0;
}
Согласно пункту 14.8.2.1 стандарта C ++, когда параметр шаблона используется только в невыведенном контексте, соответствующий аргумент шаблона не может быть выведен:
Если параметр шаблона не используется ни в одной функции параметры шаблона функции, или используется только в невыведенном контексте, соответствующий ему аргумент-шаблон не может быть выведен из вызова функции, а аргумент-шаблон должен быть явно указан .
Определение невыведенных контекстов, как указано в §14.8.2.4:
Невыведенные контексты:
спецификатор вложенного имени типа, который был указан с помощью квалифицированный идентификатор .
Тип, который является идентификатором шаблона , в котором один или несколько из аргументов шаблона являются выражением, которое ссылается на параметр шаблона .
В Bar
, Bar
является описателем вложенного имени и, следовательно, невыведенным контекстом, поэтому вы должны явно указать аргумент шаблона при вызове конструктора ... что невозможно (т.е. вы не можете написать Foo f
).
Я полагаю, что компилятор не может вывести аргумент шаблона, потому что это было бы по крайней мере громоздко и, скорее всего, невозможно: представьте, что Bar специализирован:
template<typename T>
struct Bar
{
typedef std::pair<T,T> type;
};
template<>
struct Bar<char>
{
typedef std::pair<int,int> type;
};
Теперь у меня есть двусмысленность при вызове конструктора Foo с std :: vector
: должен ли аргумент шаблона быть int
или char
? И даже если бы такой двусмысленности не было, вы можете легко увидеть, что компилятору пришлось бы создать экземпляр Bar с потенциально любым типом, прежде чем найти экземпляр с правильным typedef (ну, я не уверен, что приведенные выше утверждения действительно актуальны, так как я часто выясни, что компиляторы намного умнее, чем я думал: -)!)
Ваш конструктор:
template <typename T>
explicit
Foo( const std::vector<typename Bar<T>::type>& data )
Аргумент шаблона T
не может быть выведен из аргумента функций таким образом. (Я думаю, что это называется «не выделенным контекстом», но я не уверен.)
Это просто не будет работать. Вам придется записать
template <typename B>
explicit
Foo( const std::vector<B>& data )
вместо этого и найти другие способы утверждать, что B
имеет тип TypeName Bar
.
Я думаю, что единственная причина для той в том, что вы хотите создать сводную строку соответствующего типа вместо печати «Hello».
Возможно, вы могли бы попробовать отобразить типы в обращенном направлении (вид обратного вычета, который вы надеетесь, что компилятор сможет выполнить):
#include <utility>
#include <vector>
template <class T>
struct BarType;
template <class T>
struct BarType<std::pair<T, T> >
{
typedef T type;
};
template <class T>
struct Bar {};
struct Foo
{
template <class T>
Foo(const std::vector<T>& )
{
Bar<typename BarType<T>::type> bar;
//...
}
};
int main()
{
Foo(std::vector<std::pair<int, int> >());
}
Может ли что-нибудь подобное сработать для вас?
#include <vector>
#include <iostream>
#include <utility>
#include <boost/static_assert.hpp>
template <typename T>
struct Bar
{
typedef std::pair<T, T> type; // or anything else that uses T
enum {val = 42};
};
template <typename T>
struct Traits
{
enum {allowed = false};
};
template <typename T>
struct Traits<std::pair<T, T> >
{
enum {allowed = true};
typedef Bar<T> BarType;
};
struct Foo
{
Foo() {}
template <typename T> explicit Foo( const std::vector<T>& data )
{
BOOST_STATIC_ASSERT(Traits<T>::allowed);
typedef typename Traits<T>::BarType BarType;
std::cout << BarType::val << std::endl;
}
};
int main()
{
std::vector<Bar<int>::type> v;
std::vector<float> v2;
Foo f( v );
// Foo f2( v2 ); // Compile error
return 0;
}
Это компилируется и работает на GCC 4.4.1. Вы можете специализироваться на Traits
для других векторов::value_type
, которые разрешены вашим конструктором.