Pull to refresh
31
0

User

Send message
Статья, действительно, хорошая. Хотелось бы сказать, что, кому интересно, — следите ещё за статьями на reddit-е — выкладывается новый и хороший материал. Например, ссылка на оригинал это статьи — была выложена ещё 3 месяца назад.
Спасибо за перевод.
Кто-нибудь видел перевод «perfect-forwarding» на русский как-то иначе, чем «идеальная передача»? Может, есть какие-то другие варианты перевода?
Да интересно, но, наверное, придётся оговариваться, что вот такие имена функций-членов класса — зарезервивованы — и ни в коем случае не используйте их! Так как приоритет у функции-члена — выше. И, действительно, как уже сказали выше — это breaking changes.
(В действительности, ситуация аналогична той же в C++, за той разницей, что C++ позволит вам сделать кучу глупых ошибок и не даёт каких-либо гарантий работы с памятью. Не спорьте со мной по этому поводу, здесь я лишь цитирую других людей, я не знаю C++ в должной степени.)

Мне нравится, как в каждой статье о Rust, упоминается ужасный и неконтролируемый C++ с кучей проблем. В данной ситуации — статья — чисто о Rust — никаких сравнений с C++ — нет, и если Вы (автор оригинальной статьи) что-то, где-то слышали, что, мол C++ «Ужас и боль», то это не значит, что об этом нужно упоминать беспричинно и безаргументно. Просто ужасно надоело этот шаблон: «Вот — язык Х, а в С++ — будут страшные проблемы, если сделать так же». И в 90% приводится код, который на плюсах никто и никогда не пишет.
Нет, он не инклудит сам себя, Вы смотрите файлы в папке \boost\preprocessor\slot.
И файл counter.hpp (который у вас в комментарии) инклудит файл detail\counter.hpp, а вот BOOST_PP_SLOT_CC_*, который в def.hpp, как раз «склеивает» разряды числа.
Файлы (и расположение) одинаковы в 2х версиях буста, которые у меня есть (1.55 и 1.56).
По поводу:
Как, черт побери, работает BOOST_PP_COUNTER?! Даже на stackoverflow ответом на соответствующий вопрос является «magic».

Я не использовал BOOST_PP_COUNTER, но мне стало интересно. Насколько я понял, всё сводится к следующему:
// File counter.hpp
#ifndef COUNTER_H_
#define COUNTER_H_

// Начальное значение
#define COUNTER 0

// Файлик, при включении которого будет происходить
// прибавление еденицы к текущему значению и, вообще,
// вся магия
#define UPDATE_COUNTER() "counter_inc.hpp"

#endif


// File counter_inc.hpp

// Увеличиваем текущее значение,
// сохраняем во временную переменную
#define INC_COUNTER COUNTER + 1

// Удаляем старое значение,
// ниже будет определено новое
#undef COUNTER

// Грубо говоря, вся суть сводится к этому, но
// не так просто: текущее значение @INC_COUNTER
// разбирается на 10 разрядов (смотри 
// boost\preprocessor\slot\detail\shared.hpp),
// которые потом собираются вместе в @COUNTER (
// смотри t_1_56_0\boost\preprocessor\slot\detail\counter.hpp):
// # if BOOST_PP_COUNTER_DIGIT_10
// #    define BOOST_PP_COUNTER BOOST_PP_SLOT_CC_10(BOOST_PP_COUNTER_DIGIT_10, /*ещё разряды*/ BOOST_PP_COUNTER_DIGIT_1)
// # elif BOOST_PP_COUNTER_DIGIT_9
// ...
// 
// 
// Т.е. максимальное значение @BOOST_PP_COUNTER состоит
// из 10 разрядов: 999999999.
#if(INC_COUNTER == 0)
# define COUNTER 0
#elif(INC_COUNTER == 1)
# define COUNTER 1
// ...
#endif

// Удаляем временную переменную
#undef INC_COUNTER



// main.cpp

#include <iostream>
#include "counter.hpp"

#include UPDATE_COUNTER()

int main()
{
	std::cout << COUNTER << std::endl;
}
Так, всё-же, в С++ нет методов, есть Member Functions, может подправите заголовок статьи?
Классический Win32 API — это С. До 8й виндовс — паралельно и ненавязчиво было (и есть) очень много API, который доступен через COM. А вот вам Windows Runtime:
WinRT is implemented in the C++ programming language[4] and is object-oriented by design.[4] (Its predecessor, Win32 API is written mostly in the C programming language.[5]) It is an unmanaged application programming interface (API) based on Component Object Model (COM) that allows interfacing from multiple languages, just as COM does

Так что я бы сказал, что COM — живее всех живых
Ничего они не закопали, всё как раз таки наоборот. Посмотрите на API новых виндовс
Оу, судя по минусам мой комментарий не только не в тему, но и показывает, что 60%, всё-таки, избавились от С++03. Поздравляю!
Потому что коллеги вас растерзают за такой код, а сисадмин и менеджер не захотят переходить на C++14 там наверняка где-то внутри бегает пара проблем, связанных с обработкой ссылок.

Боже, какой С++14! Тут, кое-кто, не может на 11й перейти!
Сравнили бы для ленивых с чем-то, например, gtest.
Кстати, можете добавить более развёрнутые размышления на эту тему от Sutter-а: Why Not Specialize Function Templates?. Там хорошо разжёвано. Например, указано, что в случае (3) — мы имеем перегрузку функции (second base template, overloads (1)) и что явные специализации не перегружают (Specializations don't overload), отсюда и всё вытекает.
Те кто ответил 3 и 6 могут сегодня потратить на торчание на хабре на полчаса больше рабочего времени чем обычно.

Что-то я запутался, может, наоборот — «меньше»? Ведь, не нужно читать статью до конца. Или — время не потраченное на эту статью — можно потратить на какую-то другую? Но тогда, время «торчания» на хабре не изменится? оО
Она, мне лично, больше нравится, так как позволяет писать
typedef TypeList<int,char,bool,string, EmptyList> MyTypeList;

Внесу и свой костыль:
template<
	typename T0 = internal::Void,
        // ...
>
struct make_typelist
{
	typedef List<T0, List<T1, List<T2, List<T3, List<T4, List<T5, List<T6, List<T7, List<T8, List<T9> > > > > > > > > > type;
};
typedef make_typelist<int, short, double, char>::type ...

Так как мне не нравится указывать что-то EmptyList-а.
А если задача состоит только в ограничении типов, которыми можно инстанциировать шаблон, то, как по мне, проще что-то такого:
template<typename T>
void foo(int x, typename std::enable_if</*Проверить, есть ли тип T в каком-то списке типов*/>::type* = NULL)
{
}

template<typename T, typename = typename std::enable_if</**/>::type>
struct Foo
{
};

Это прекрасно работает и не приходится инстанциировать весь набор, а только то, что нужно
Я просто думал, что смогу для себя объяснить это в рамках overload resolution (Вот хорошее видео от Stephan T. Lavavej — Overload Resolution).

Вроде как даже нашёл: 13.3.1.4 Copy-initialization of class by user-defined conversion (n3797)
...the candidate functions are selected as follows:

...When initializing a temporary to be bound to the first parameter
of a constructor that takes a reference to possibly cv-qualified T as its first argument, called with a
single argument in the context of direct-initialization of an object of type “cv2 T”, explicit conversion
functions are also considered…

И 13.3.1 Candidate functions and argument lists:
A defaulted move constructor or assignment operator (12.8) that is defined as deleted is excluded from the
set of candidate functions in all contexts.

Но это не то, скорее всего
Я запутался.
Есть класс (структура, не важно):
struct Test
{
	Test() : s("s") {}
	Test(const Test& other) : s(other.s) { puts("Test(const Test& other)"); }
	std::string s;
};

В этом случае неявный move-constructor не создаётся (По схеме: дважды Нет).
Должен ли компилироваться следующий код?
int main()
{
	Test t1{};
	Test t2(std::move(t1));

	puts(t1.s.c_str());
	puts(t2.s.c_str());
	return 0;
}

Ответ — всё в порядке — компилируется и вызывается копирующий конструктор:
Test(const Test& other)
s
s

Почему? Я как-то не правильно понимаю когда вызывается copy ctor? (Copy constructors):
The copy constructor is called whenever an object is initialized from another object of the same type, which includes

initialization, T a = b; or T a(b);, where b is of type T

function argument passing: f(a);, where a is of type T and f is void f(T t)

function return: return a; inside a function such as T f(), where a is of type T, which has no move constructor.


Если же явно попросить компилятор сгенерировать move-конструктор, то уже действительно вызывается move-конструктор:
struct Test
{
	Test() : s("s") {}
	Test(const Test& other) : s(other.s) { puts("Test(const Test& other)"); }
	Test(Test&& other) = default;
	std::string s;
};
//...

s

Если же явно запретить компилятору генерировать move-конструктор:
struct Test
{
	Test() : s("s") {}
	Test(const Test& other) : s(other.s) { puts("Test(const Test& other)"); }
	Test(Test&& other) = delete;
	std::string s;
};

Тогда уже компилятор ругается!
Что получается:
Test t2(std::move(t1));

Если move-конструктор неявно НЕ сгенерирован, то вызывается copy-constructor
Если move-конструктор явно помечен через delete, то copy-constructor НЕ вызывается

Я окончательно запутался. Пошёл смотреть стандарт :(
Да, думаю не плохо будет.
И ещё вот, например, этот сайт выглядит вот-так:

При открытии в новой вкладке — всё ок.
Очень круто. Спасибо!
Было бы не плохо сразу же прогружать первую ссылку…
Понял, я придирчив. Спасибо

Information

Rating
Does not participate
Location
Киев, Киевская обл., Украина
Registered
Activity