Шаблонный конструктор C++ не скомпилирует

Каким образом я не могу инстанцировать объекта типа 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;
}
7
задан kmhofmann 26 January 2010 в 14:35
поделиться

4 ответа

Согласно пункту 14.8.2.1 стандарта C ++, когда параметр шаблона используется только в невыведенном контексте, соответствующий аргумент шаблона не может быть выведен:

Если параметр шаблона не используется ни в одной функции параметры шаблона функции, или используется только в невыведенном контексте, соответствующий ему аргумент-шаблон не может быть выведен из вызова функции, а аргумент-шаблон должен быть явно указан .

Определение невыведенных контекстов, как указано в §14.8.2.4:

Невыведенные контексты:

  • спецификатор вложенного имени типа, который был указан с помощью квалифицированный идентификатор .

  • Тип, который является идентификатором шаблона , в котором один или несколько из аргументов шаблона являются выражением, которое ссылается на параметр шаблона .

В Bar :: type , Bar является описателем вложенного имени и, следовательно, невыведенным контекстом, поэтому вы должны явно указать аргумент шаблона при вызове конструктора ... что невозможно (т.е. вы не можете написать Foo f (v) ).

Я полагаю, что компилятор не может вывести аргумент шаблона, потому что это было бы по крайней мере громоздко и, скорее всего, невозможно: представьте, что 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 (ну, я не уверен, что приведенные выше утверждения действительно актуальны, так как я часто выясни, что компиляторы намного умнее, чем я думал: -)!)

10
ответ дан 6 December 2019 в 15:22
поделиться

Ваш конструктор:

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 :: Тип .

4
ответ дан 6 December 2019 в 15:22
поделиться

Я думаю, что единственная причина для той в том, что вы хотите создать сводную строку соответствующего типа вместо печати «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> >());
}
0
ответ дан 6 December 2019 в 15:22
поделиться

Может ли что-нибудь подобное сработать для вас?

#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, которые разрешены вашим конструктором.

0
ответ дан 6 December 2019 в 15:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: