SFINAE? compiler bug?
От: Sergey Россия  
Дата: 24.09.07 11:47
Оценка:
Есть такой код:

#include <vector>

class Bar
{
 friend void TestOverload();
 int x;
 Bar(const Bar&);
 Bar& operator=(const Bar&);
protected:
 Bar() : x(0) {}
 virtual ~Bar() = 0;
};

Bar::~Bar()
{}

struct BarC : Bar
{
 ~BarC() {}
};

template <class X> void foo(X &x, const std::vector<bool> &t)
{
 ;
}

template <class T> void foo(Bar &x, const std::vector<T> &t)
{
 ;
}

void foo(Bar &x, const std::vector<bool> &t)
{
 foo<Bar>(x, t);
}

void Impl(Bar &x)
{
 std::vector<bool> v;
 foo(x, v);
}

void TestOverload()
{
 BarC x;
 Impl(x);
}


Оный код успешно компилируется Comeau online и не компилируется VC8 sp1:
1>c:\program files (x86)\microsoft visual studio 8\vc\include\vector(693) : error C2259: 'Bar' : cannot instantiate abstract class
1> due to following members:
1> 'Bar::~Bar(void)' : is abstract
1> c:\projects\testsoap\testsoap\testoverload.cpp(12) : see declaration of 'Bar::~Bar'
1> c:\projects\testsoap\testsoap\testoverload.cpp(35) : see reference to class template instantiation 'std::vector<_Ty,_Ax>' being compiled
1> with
1> [
1> _Ty=Bar,
1> _Ax=std::allocator<Bar>
1> ]

Т.е., очевидно, компилятор пытается инстанцировать template <class T> void foo(Bar &x, const std::vector<T> &t) для T==Bar, это, естественно, у него не получается, и тут вдруг вместо того, чтобы подставить template <class X> void foo(X &x, const std::vector<bool> &t) выдает ошибку компилляции. Если же лишить класс Bar чисто виртуальных функций, все странным образом собирается и работает, хотя vector<Bar> по прежнему не может быть инстанцирован — у Bar закрыты конструкторы и деструктор.
Собственно, вопросов два:
1) Я ничего не напутал и это действительно ошибка компилятора?
2) Как бы тут извратиться и все-таки суметь компилировать подобный код, с учетом того, что класс Bar и первый вариант функции foo (который template <class X> void foo(X &x, const std::vector<bool> &t) ) — сущности библиотечные и менять их крайне нежелательно.
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re: SFINAE? compiler bug?
От: remark Россия http://www.1024cores.net/
Дата: 24.09.07 12:04
Оценка: 21 (1)
Здравствуйте, Sergey, Вы писали:

S>Т.е., очевидно, компилятор пытается инстанцировать template <class T> void foo(Bar &x, const std::vector<T> &t) для T==Bar, это, естественно, у него не получается, и тут вдруг вместо того, чтобы подставить template <class X> void foo(X &x, const std::vector<bool> &t) выдает ошибку компилляции. Если же лишить класс Bar чисто виртуальных функций, все странным образом собирается и работает, хотя vector<Bar> по прежнему не может быть инстанцирован — у Bar закрыты конструкторы и деструктор.


Во-первых, 14.7.1/5

If the overload resolution process can determine the correct function
to call without instantiating a class template definition, it is
unspecified whether that instantiation actually takes place. [Exam-
ple:
template <class T> struct S {
operator int();
};

void f(int);
void f(S<int>&);
void f(S<float>);

void g(S<int>& sr) {
f(sr); // instantiation of S<int> allowed but not required
// instantiation of S<float> allowed but not required
};
--end example]


Т.е. std::vector<Bar> может инстанциироваться в любом случае. Поведение unspecified. Поэтому разные компиляторы и компилируют по-разному.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: SFINAE? compiler bug?
От: remark Россия http://www.1024cores.net/
Дата: 24.09.07 12:17
Оценка:
Здравствуйте, remark, Вы писали:

R>Во-первых, 14.7.1/5

R>

R>If the overload resolution process can determine the correct function
R> to call without instantiating a class template definition, it is
R> unspecified whether that instantiation actually takes place. [Exam-
R> ple:
R> template <class T> struct S {
R> operator int();
R> };

R> void f(int);
R> void f(S<int>&);
R> void f(S<float>);

R> void g(S<int>& sr) {
R> f(sr); // instantiation of S<int> allowed but not required
R> // instantiation of S<float> allowed but not required
R> };
R> --end example]


R>Т.е. std::vector<Bar> может инстанциироваться в любом случае. Поведение unspecified. Поэтому разные компиляторы и компилируют по-разному.



Во-вторых, что бы воспользоваться SFINAE тебе надо сделать так, что бы получающееся выражение было синтаксически некорректным, а не просто приводило бы когда-то к какой-то ошибке. Например, ошибке линковки или ран-тайм ошибке.
В твоём случае std::vector<Bar> синтаксически корректно, и при этом само это выражение не приводит к инстанциированию функций-членов std::vector<Bar>, в которых как раз уже и пытаются создать абстрактный класс. Поэтому на фазе поиска подходящих функций невозможно ничего определить.


R>


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: SFINAE? compiler bug?
От: remark Россия http://www.1024cores.net/
Дата: 24.09.07 12:20
Оценка:
Здравствуйте, remark, Вы писали:

R>Во-вторых, что бы воспользоваться SFINAE тебе надо сделать так, что бы получающееся выражение было синтаксически некорректным, а не просто приводило бы когда-то к какой-то ошибке. Например, ошибке линковки или ран-тайм ошибке.

R>В твоём случае std::vector<Bar> синтаксически корректно, и при этом само это выражение не приводит к инстанциированию функций-членов std::vector<Bar>, в которых как раз уже и пытаются создать абстрактный класс. Поэтому на фазе поиска подходящих функций невозможно ничего определить.


В-третьих, тебе надо определиться, когда ты хочешь, что бы какая функция вызывалась.
Т.к. при таком определении как ты дал для некоторых комбинаций аргументов может вызываться и та и та функция. Как собственно ты в примере и привёл.

Вот, например, вариант, когда мы не хотим вызывать вторую функцию, когда второй параметр std::vector<bool>:

#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_same.hpp>

template <class T> typename boost::enable_if<typename boost::is_same<T, bool>::result>::result foo(Bar &x, const std::vector<T> &t)
{
 ;
}



R>>

R>

1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: SFINAE? compiler bug?
От: Sergey Россия  
Дата: 24.09.07 12:34
Оценка:
"remark" <38267@users.rsdn.ru> wrote in message news:2668540@news.rsdn.ru...
> Здравствуйте, remark, Вы писали:
>
> R>Во-вторых, что бы воспользоваться SFINAE тебе надо сделать так, что бы получающееся выражение было синтаксически некорректным, а не просто приводило бы когда-то к какой-то ошибке. Например, ошибке линковки или ран-тайм ошибке.
> R>В твоём случае std::vector<Bar> синтаксически корректно, и при этом само это выражение не приводит к инстанциированию функций-членов std::vector<Bar>, в которых как раз уже и пытаются создать абстрактный класс. Поэтому на фазе поиска подходящих функций невозможно ничего определить.
>
>
> В-третьих, тебе надо определиться, когда ты хочешь, что бы какая функция вызывалась.
> Т.к. при таком определении как ты дал для некоторых комбинаций аргументов может вызываться и та и та функция. Как собственно ты в примере и привёл.
>
> Вот, например, вариант, когда мы не хотим вызывать вторую функцию, когда второй параметр std::vector<bool>:
>
>
> #include <boost/utility/enable_if.hpp>
> #include <boost/type_traits/is_same.hpp>
> 
> template <class T> typename boost::enable_if<typename boost::is_same<T, bool>::result>::result foo(Bar &x, const std::vector<T> &t)
> {
> ;
> }
>

>
>
> R>>
> R>
>

А я пока остановился на таком:
template <class T> void foo(Bar &x, const std::vector<T> &t, typename boost::enable_if<boost::mpl::not_<boost::is_abstract<T> > >::type* dummy = 0)

{

;

}
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re: SFINAE? compiler bug?
От: Павел Кузнецов  
Дата: 24.09.07 12:35
Оценка: 14 (1)
Здравствуйте, Sergey, Вы писали:

S>
S>template <class X> void foo(X &x, const std::vector<bool> &t)

S>template <class T> void foo(Bar &x, const std::vector<T> &t)

S>void foo(Bar &x, const std::vector<bool> &t)
S>{
S> foo<Bar>(x, t);
S>}
S>


S>2) Как бы тут извратиться и все-таки суметь компилировать подобный код, с учетом того, что класс Bar и первый вариант функции foo (который template <class X> void foo(X &x, const std::vector<bool> &t) ) — сущности библиотечные и менять их крайне нежелательно.


Например, введя "уровень косвенности":
template <class X> void foo(X &x, const std::vector<bool> &t) { }

template <class T> void foo_(Bar &x, const std::vector<T> &t) { }

template<class X, class T> struct foo_caller;

template<class X> struct foo_caller<X, bool>
{
  static void call(X& x, std::vector<bool> const& t) { foo(x, t); }
};

template<class T> struct foo_caller<Bar, T>
{
  static void call(Bar& x, std::vector<T> const& t) { foo_(x, t); }
};

template<> struct foo_caller<Bar, bool>
{
  static void call(Bar& x, std::vector<bool> const& t) { foo(x, t); }
};

template<class X, class T> void foo(X &x, const std::vector<T> &t)
{
 foo_caller<X, T>::call(x, t);
}
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re: SFINAE? compiler bug?
От: Кодт Россия  
Дата: 24.09.07 12:39
Оценка:
Здравствуйте, Sergey, Вы писали:

S>template <class X> void foo(X &x, const std::vector<bool> &t) { }
S>template <class T> void foo(Bar &x, const std::vector<T> &t) { }

S>void foo(Bar &x, const std::vector<bool> &t)
S>{
S> foo<Bar>(x, t);
S>}


S>Оный код успешно компилируется Comeau online и не компилируется VC8 sp1:

S>Т.е., очевидно, компилятор пытается инстанцировать template <class T> void foo(Bar &x, const std::vector<T> &t) для T==Bar, это, естественно, у него не получается, и тут вдруг вместо того, чтобы подставить template <class X> void foo(X &x, const std::vector<bool> &t) выдает ошибку компилляции. Если же лишить класс Bar чисто виртуальных функций, все странным образом собирается и работает, хотя vector<Bar> по прежнему не может быть инстанцирован — у Bar закрыты конструкторы и деструктор.

Почему компилируется, когда закрыты члены — это понятно.
Шаблон vector<Bar> инстанцируется не весь, а лишь по мере необходимости. Нужен конструктор без параметров — сделаем. Не нужен — не сделаем.
При передаче по ссылке, очевидно, ничего больше не потребовалось. Поэтому private/protected не оказали влияние.

Почему компилятор ориентируется на наличие/отсутствие абстрактных функций у класса — не знаю. В принципе, должно было быть пофиг. (А если бы вместо std::vector был boost::shared_ptr, которому на абстракцию плевать?)
Скорее всего (имхо), комо и студия просто ткнули пальцем в небо и пошли разными путями. Комо угадал твои желания, а студия — нет.

S>Собственно, вопросов два:

S>1) Я ничего не напутал и это действительно ошибка компилятора?

Ещё неизвестно, ошибка какого компилятора...
И что за ошибка...

S>2) Как бы тут извратиться и все-таки суметь компилировать подобный код, с учетом того, что класс Bar и первый вариант функции foo (который template <class X> void foo(X &x, const std::vector<bool> &t) ) — сущности библиотечные и менять их крайне нежелательно.


Как бы так извратиться, чтобы не смешивать указание и вывод параметров шаблона.
Вот, не смотря на содержание класса Bar, ты можешь определить, foo<Bar> относится к какому из шаблонов
— template<class X> void foo(X&, const vector<bool>&)
— template<class T> void foo(Bar&, const vector<T>&)
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[5]: SFINAE? compiler bug?
От: Аноним  
Дата: 24.09.07 13:24
Оценка:
Здравствуйте, Sergey, Вы писали:

1. если я не ошибаюсь SFINAE а тут точно тену если
2. в данной ситуации те boost::enable_if слишком шекарно.
3. и вопрос а почему у тебя деструктор чисто виртуальный?
леши класс абстракции и все скомпильится.(и protected за одно если конечно тебя это устраевает)
Re[2]: SFINAE? compiler bug?
От: Sergey Россия  
Дата: 24.09.07 13:28
Оценка:
> Почему компилируется, когда закрыты члены — это понятно.
> Шаблон vector<Bar> инстанцируется не весь, а лишь по мере необходимости. Нужен конструктор без параметров — сделаем. Не нужен — не сделаем.
> При передаче по ссылке, очевидно, ничего больше не потребовалось. Поэтому private/protected не оказали влияние.

На самом деле, потребовалось. Я проверял, при комментировании "правильной" функции не компилируется даже при отсутствии чисто виртуальных функций в классе Bar.

> S>2) Как бы тут извратиться и все-таки суметь компилировать подобный код, с учетом того, что класс Bar и первый вариант функции foo (который template <class X> void foo(X &x, const std::vector<bool> &t) ) — сущности библиотечные и менять их крайне нежелательно.

>
> Как бы так извратиться, чтобы не смешивать указание и вывод параметров шаблона.
> Вот, не смотря на содержание класса Bar, ты можешь определить, foo<Bar> относится к какому из шаблонов
> — template<class X> void foo(X&, const vector<bool>&)
> — template<class T> void foo(Bar&, const vector<T>&)

Ничего не понял
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[3]: SFINAE? compiler bug?
От: Кодт Россия  
Дата: 24.09.07 14:19
Оценка:
Здравствуйте, Sergey, Вы писали:

>> Как бы так извратиться, чтобы не смешивать указание и вывод параметров шаблона.

>> Вот, не смотря на содержание класса Bar, ты можешь определить, foo<Bar> относится к какому из шаблонов
>> — template<class X> void foo(X&, const vector<bool>&)
>> — template<class T> void foo(Bar&, const vector<T>&)

S>Ничего не понял


Вот и я "ничего не понял". У тебя два разных шаблона функции foo, каждый из которых — с единственным параметром. К которому из них относится foo<Bar>?
Если бы параметры выводились компилятором из аргументов — никаких проблем, это обобщение ситуации с перегрузкой функций.

Это я к тому, что явная параметризация шаблона функции — зло. Оно имеет право на существование лишь в том случае, когда гарантируется, что шаблон единственный — раз уж язык позволяет объявлять множество разнородных функций и их шаблонов с одинаковым именем.

Вот с шаблонами классов такой фокус не прошёл бы. Там чётко: одно имя — один шаблон.
Хотя, если припахать нетривиальный поиск имён, то можно тоже довести компилятор и разработчика до истерики. (Особенно — разработчика).
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[4]: SFINAE? compiler bug?
От: Sergey Россия  
Дата: 24.09.07 14:44
Оценка:
>>> Как бы так извратиться, чтобы не смешивать указание и вывод параметров шаблона.
>>> Вот, не смотря на содержание класса Bar, ты можешь определить, foo<Bar> относится к какому из шаблонов
>>> — template<class X> void foo(X&, const vector<bool>&)
>>> — template<class T> void foo(Bar&, const vector<T>&)
>
> S>Ничего не понял
>
> Вот и я "ничего не понял". У тебя два разных шаблона функции foo, каждый из которых — с единственным параметром. К которому из них относится foo<Bar>?
> Если бы параметры выводились компилятором из аргументов — никаких проблем, это обобщение ситуации с перегрузкой функций.

Параметры в данном случае как раз и выводятся компилятором из аргументов.

> Это я к тому, что явная параметризация шаблона функции — зло.


Здесь она нужна только для того, чтобы отличить вызов шаблонной функции от вызова нешаблонной (в реальном коде они все шаблонные, но с разным числом параметров).

> Оно имеет право на существование лишь в том случае, когда гарантируется, что шаблон единственный — раз уж язык позволяет объявлять множество разнородных функций и их шаблонов с одинаковым именем.


На самом деле, мне просто деваться особо некуда. Надо перехватить вызов библиотечной функции, причем вызывается она тоже из библиотечного кода. Вообще-то это просто перегрузка boost::serialization::save для векторов. Хочется для некоторого типа архивов вызывать сначала мою функцию, из нее — библиотечную. Я не стал про это сразу писать, чтобы не отвлекать обсуждение в сторону буста и т.п.

> Вот с шаблонами классов такой фокус не прошёл бы. Там чётко: одно имя — один шаблон.

> Хотя, если припахать нетривиальный поиск имён, то можно тоже довести компилятор и разработчика до истерики. (Особенно — разработчика).

С шаблонами классов хватило бы частичной специализации.
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[5]: SFINAE? compiler bug?
От: Кодт Россия  
Дата: 24.09.07 16:53
Оценка:
Здравствуйте, Sergey, Вы писали:

S>С шаблонами классов хватило бы частичной специализации.


Дело в том, что частичная специализация шаблона класса — это ОДИН шаблон, состоящий из основной версии (наиболее общей) и множества специализаций.
А россыпь шаблонов перегруженных функций — это именно РОССЫПЬ.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.