decltype in lambda


decltype is to calculate type from object expression
Demonstrated by the lambda used to initialize std::set
decltype is required since that’s the only way to access the type of the lambda when the lambda is embedded.

lambda is no more than syntactic shortcut to functor.

void TestLambdaInSet()
{
	bool bGreat = true;
	auto cmp = [=, &bGreat](int a, int b)
	{
		if (bGreat)
			return a > b;
		else
			return a < b;
	};
	std::set myset(cmp);
	myset.insert(1); myset.insert(2);
	printf("first item should be greatest since bGreat = true. got %d", *myset.begin());
	//output is 2 as expected
	bGreat = false;
	myset.clear();
	myset.insert(1); myset.insert(2);
	printf("first item should be smallest since bGreat = false. got %d", *myset.begin());
	//output is 1 as expected
}

void main()
{
	TestLambdaInSet();
}
Advertisements

Perfect Forwarding: std::forward and std::move


Based on the source code below, here is the forwarding result:
Input parameter                    Forwarded to
int intNonConst:                     (int&)
const int intConst:                  (const int&)
6(just a literal):                        (int&&) or if (int&&) doesn’t exist, to (const int& i)
std::move(intNonConst)):      (int&&)
int IntTemp():                          (int&&)
Why std::forward: otherwise, when a rvalue is passed, e.g. 6, std::move or IntTemp(), it gets forwarded to &, instead of &&.
Why std::move: so that a lvalue such as intNonConst can be treated as rvalue, and therefore be forwarded to &&
Summary: std::forward is to deal with rvalue forwarding, and it does not affect rvalue reference, regardless of constness

int IntTemp() { return 0; }
void TestForwardingFuncCalled(const int& i)
{
	cout << "const &" << endl;
};
void TestForwardingFuncCalled(int& i)
{
	cout << "&" << endl;
};
void TestForwardingFuncCalled(int&& i)
{
	cout << "&& " << endl;
};

template  void TestForwardingTemplateFunc(T&& t)
{
	cout << "Results with std::forward" << endl;
	TestForwardingFuncCalled(std::forward(t));
	cout << "Results without std::forward" << endl;
	TestForwardingFuncCalled(t);
}

void TestForwarding()
{
	int intNonConst = 2;
	const int intConst = 3;
	TestForwardingTemplateFunc(intNonConst); //with std::forward: (int&)", without std::forward: same
	TestForwardingTemplateFunc(intConst); //with std::forward: (const int&)", without std::forward: same
	TestForwardingTemplateFunc(6); //with std::forward: (int&&) or if (int&&) doesn't exist, to (const int& i), without std::forward: (int&)
	TestForwardingTemplateFunc(std::move(intNonConst)); //with std::forward: (int&&), without std::forward: (int&)
	TestForwardingTemplateFunc(IntTemp());  //with std::forward: (int&&), without std::forward: (int&)
}
void main()
{
	TestForwarding();
}

 

typename vs class (Visual Studio 2010)


Under what circumstances does NOT ‘class’ replace ‘typename’?

struct C
{
class CC{};
typedef CC CC2;
};
template<class T> //using 'class' is fine
struct D
{
typename T::CC2 c1; //'typename' cannot be prelaced by 'class'
class T::CC c2; //using 'class' is fine
//T::CC c3; //error: 'T::CC' : dependent name is not a type
//class T::CC2 c4; //error C2242: typedef name cannot follow class/struct/union
//T::CC2 c5; //error: 'T::CC2' : dependent name is not a type
};
D<C> a;

Summary: if the subtype if not typedef-ed, class can do the job of typename.
Otherwise, it has to be typename.

A minimum iterator template that works with ostream_iterator


This iterator works with std::ostream_iterator to get the container’s content printed to cout.
It’s minimum because it stops working if I take one more element out.
Minimum snippets is best to show how things work under the hood.

template <class T> class CMyContainer
{
public:
	enum {MAX = 2}; //only hold two elements
protected:
    T maData[MAX];
public:
    CMyContainer<T>(const T& t1, const T& t2)
	{
		maData[0] = t1; maData[1] = t2; //pre-initialized to only 2 element
	}
    class iterator;
    iterator begin()
	{
		return iterator(0, this);
	}
    iterator end()
	{
		return iterator(MAX, this);
	}
};
template <class T> class CMyContainer<T>::iterator
{
    CMyContainer<T> * mpContainer;
    int miIndex;
public:
	typedef std::forward_iterator_tag iterator_category;
	typedef void value_type;
	typedef void difference_type;
	typedef void distance_type;
	typedef void pointer;
	typedef void reference;
    iterator () {}
    iterator (int iIndex, CMyContainer<T> * c): miIndex(iIndex), mpContainer(c) {}
    bool operator==(const iterator & z)
	{
		return miIndex == z.miIndex;
	}
    bool operator!=(const iterator & z)
	{
		return !operator==(z);
	}
    void operator++()
	{
		++ miIndex;
    }
    T& operator*()
	{
		return mpContainer->maData[miIndex];
	}
};

void TestCustomIterator()
{
	CMyContainer<int> b(1, 2);
	CMyContainer<int>::iterator it;
	ostream_iterator<int> o(cout, " ");
	copy(b.begin(), b.end(), o); //this line prints 1 2 (content of b)
}