Archive

Posts Tagged ‘templates’

An implementation of generic lambdas (request for feedback)

December 24, 2012 Leave a comment

An implementation of generic lambdas (request for feedback)

Faisal Vali has created an initial, alpha implementation (in Clang) of the current Generic (Polymorphic) Lambda Expressions proposal (N3418). This would see the addition of support for templated lambda expressions; the current state achieves this either via explicit parameter list after the lambda introducer, or by using the ‘auto’ keyword in place of a typename.

The article links to an interesting (FSVO interesting) discussion of the proposal, and the Clang source with support for it.

Categories: Uncategorized Tags: , , ,

Eric Niebler: stupid name lookup

December 17, 2012 Leave a comment

Eric Niebler: stupid name lookup

Eric Niebler shows a name lookup failure caused by a recursive template function inferring its return type via decltype. Stupid problem with a rather nasty hacky workaround, but also a likely change in C++14 that will be most welcome, and makes the whole problem go away :-)

Generalised type-deduction for class template instance construction

November 19, 2012 Leave a comment

I’ll wager that most C++ developers with experience of templates have at some point discovered the limitation that a class template’s parameters cannot be deduced in construction. Since type deduction can be performed in invocation of a function template however, I commonly create a helper function such as make_wrapper in the following sample to enable type deduction to take place when I want it:

#include <type_traits>

template< class T >
struct wrapper
{
   wrapper( const T& );
};

template
wrapper make_wrapper(const T& t)
{
   return wrapper(t);
}

static_assert( std::is_same< decltype(make_wrapper(42)), wrapper >::value, "incorrect type deduction" );

Common examples of this in the standard library are make_pair, make_shared and make_tuple (the latter 2 being available in C++11 only).

The annoyance of this however is that you must write a deduced construction helper for each class template you wish to be able to perform deduced construction of. Except that’s rather untrue: you could write a deduced construction helper for each class template parameter pattern, e.g. <class>, <class, class>, <class, class, class> etc, but with the aid of C++11 language & library additions we can do better than that.

Generalising the type-deduction helper

Thanks to perfect forwarding and variadic templates it is now possible to generalise this pattern to support any template class. If you are unfamiliar with these techniques I recommend reading Sutter’s description of a make_unique function (see the section entitled Enter make_unique) and Meyers’ post on what he calls ‘universal references‘.

#include
#include <type_traits>
#include

/** Changes std::reference_wrapper to the corresponding reference type. */
template< class T >
struct unwrap {
	typedef T type;
};

template< class T >
struct unwrap< std::reference_wrapper > {
	typedef T& type;
};

template< class T >
struct unwrap< std::reference_wrapper > {
	typedef const T& type;
};

/** Deduced construction of a template class with given parameters. */
template< template class T, class... Args >
auto make( Args&&... args ) -> T< typename unwrap< typename std::decay::type >::type... >
{
	return T<
		typename unwrap<
			typename std::decay::type
		>::type...
	>( std::forward(args)... );
}

Things to note about this implementation:

  • The unwrap template and specialisations enables the call site to force a reference type in the deduction in a similar way to std::bind.
  • std::decay enables this to model function parameter passing more closely by performing certain conversions, such as array-to-pointer.
  • a noexcept constructor does not result in make being noexcept, although it should be straightforward to add support to do so.

Putting it to use

The following code sample shows how this may be used:

#include
#include
#include
#include

/** Simple wrapper class. */
template< class T >
struct wrapper
{
	explicit wrapper( const T& t_ ): t(t_) {}

	template< class U >
	explicit wrapper( U&& u )
		: t( std::forward<span style="text-decoration: underline;">(u) )
	{}

	T t;
};

/** Simple helper to clarify the assertions below. */
template< class, class >
struct assert_wrapped_type_same;

template< class T, class U >
struct assert_wrapped_type_same< wrapper, U >
{
	static_assert( std::is_same< T, U >::value, "wrapped type mismatch" );
};

int main(int, char**)
{
	// basic test from literal; copy makes from rvalue
	auto w0 = make( 42 );
	assert_wrapped_type_same< decltype(w0), int >();
	assert( w0.t == 42 );

	// basic test from lvalue: copy makes and drops const qualification
	const std::string hello("world!");
	auto w1 = make( hello );
	assert_wrapped_type_same< decltype(w1), std::string >();
	assert( w1.t == "world!" );

	// test decay from array type.
	auto w2 = make( "xyzzy" );
	assert_wrapped_type_same< decltype(w2), const char* >();
	assert( std::string(w2.t, 5) == "xyzzy" );

	// test moving a non-copyable object into makeor
	std::unique_ptr upi( new long(120623) );
	auto w3 = make( std::move(upi) );
	assert_wrapped_type_same< decltype(w3), std::unique_ptr >();
	assert( !upi );
	assert( w3.t and *w3.t == 120623 );

	// test use of reference wrappers to qualify deduced type; std::cref -> const T&
	std::string s("must go faster");
	auto w4 = make( std::cref(s) );
	assert_wrapped_type_same< decltype(w4), const std::string& >();
	assert( &w4.t == &s );

	// and std::ref -> T&
	auto w5 = make( std::ref(s) );
	assert_wrapped_type_same< decltype(w5), std::string& >();
	assert( &w5.t == &s );

	// now a sample with a variadic template
	auto tup0 = make( 42, "hello", std::string("world!"), std::unique_ptr(new long(120623) ), std::cref(s), std::ref(s) );
	static_assert(
		std::is_same< decltype(tup0), std::tuple<int, const char*, std::string, std::unique_ptr, const std::string&, std::string&> >::value,
		"tuple type mismatch" );
	assert( std::get(tup0) == 42 );
	assert( std::get(tup0) == std::string("hello") );
	assert( std::get(tup0) == std::string("world!") );
	assert( std::get(tup0) and *std::get(tup0) == 120623 );
	assert( &std::get(tup0) == &s );
	assert( &std::get(tup0) == &s );
}

You can download the complete code sample here; I have tested it successfully with gcc 4.7.2, but it won’t build on 4.6.3.

I’d love to hear what you have to say on this – whether it’s useful to you, if you have any suggestions/corrections etc.

Update, 2013-03-28

Mike Spertus and Daveed Vandevoorde have recenly submitted a standards proposal that would enable deduction of class template parameters in some constructor calls: n3602. The approach is fundamentally different from the make-based approach, which is good as that has some significant issues (not least that it only works where the template type parameter list matches the constructor parameter list).

In their approach for each of the class template’s constructors the compiler will add a function template with the same parameter list to an overload set. The template parameters can then be deduced by performing overload resolution on that set via a synthesised (i.e. pretend) call.

Compile-time binary literals [via pseudorandom noise]

November 28, 2011 Leave a comment

Compile-time binary literals [via pseudorandom noise]

This is a great post that shows off the new user-defined literals feature in C++11, using it to implement binary number literals such as 1011101010111110_binary. Paul also shows off some great template metaprogramming to achieve this end including template specialization, variadic templates (with template parameter packs and template recursion), and the sizeof... operator, which I’d not previously come across.

Quite a collection of features to discuss in one post, but done clearly and cohesively.

Template parameter deduction from array dimensions

August 24, 2011 Leave a comment

The template facility in C++ doesn’t only allow you to parameterise with types (such as the int in std::vector<int>), but also with values. Non-type template parameters can be of the following types[1]:

  • Integral (or enum) value
  • Pointer to object/function
  • Reference to object/function
  • Pointer to member

I’m going to look at the first of these types – integers – and how template parameter deduction behaves with arrays.

Template parameter deduction is the facility whereby the compiler determines how to instantiate a template when a template parameter is unspecified, e.g:

std::vector<int> vi;
std::sort(vi.begin(), vi.end());

Although we aren’t specifying the type of iterator for std::sort() to use, the compiler works it out from the parameters we provide.

Array dimensions as template parameters

We can create a function that is templated on an array’s dimensions:

#include <iostream>
#include <string>

template<int N>
void fun(std::string s[N])
{
   for (int i(0); i < N; ++i)
      std::cout << i << ": " << s[i] << std::endl;
}

int main()
{
   std::string s[2] = {"hello", "world"};
   fun<2>(s);
}

$> ./a.out
0: hello
1: world

Note that omitting the explicit template parameter in this implementation, calling in fun(s) instead, will yield a build error:
$> g++ broken.cpp
broken.cpp: In function ‘int main()’:
broken.cpp:14:9: error: no matching function for call to ‘fun(std::string [2])’

This confused me for some time, since I was under the impression that the template parameter was deducible from the array dimension.

(NB: as an aside, the above would also work if you wrote fun<500>(s); I think this is down to the array decaying to a pointer, which can then readily initialise the array parameter.)

Deduction of template parameters from array dimensions

Stroustrup’s TCPL states that[2]a compiler can deduce..a non-type template argument, I, from a template function argument with a type..type[I]“, which implies to me that the above should work fine.
I puzzled for a while over why the parameter couldn’t be deduced, and eventually hit on the answer. The standard states that a value of type “array of N T” (e.g. “array of 5 int“) can be converted to an rvalue of type “pointer to T“.[3] This means that the array size is lost in the instantiation, and as such the value of N cannot be deduced, the template instantiation fails, and – in our example above – fun() cannot be resolved.

The way to prevent this conversion (known as ‘decay’) is to declare the function parameter as a reference to an array by changing fun(string s[N]) to fun(string (&s)[N]):

template<int N>
void fun(string (&s)[N])
{
   for (int i(0); i < N; ++i)
      cout << i << ": " << s[i] << endl;
}

int main()
{
   string s[2] = {"hello", "world"};
   fun(s);
}

And it works!

Multi-dimensional arrays

Interestingly, although I haven’t declared a reference to an array in this alternate implementation with a multidimensional array, it still works fine:

template<int N>
void fun(string s[1][N])
{
   for (int i(0); i < N; ++i)
      cout << i << ": " << s[0][i] << endl;
}

int main()
{
   string s[1][2] = {{"hello", "world"}};
   fun(s);
}

The reason for this is that array decay does not happen recursively, so in the call to fun(), int[1][2] decays to a pointer to an array of 2 ints, and no further, therefore still carries the size information. (NB: I could not find authoritative evidence of this; it may be implicit in that the standard doesn’t state that it should happen recursively.)

Footnotes

  • 1 This is the list as specified for C++98 and 03 (cf. ISO C++ standard 14882 14.1.4); C++11 has a few additions.
  • 2 Stroustrup – The C++ Programming Language, Special Edition; Appendix C.13.4 – Deducing Function Template Arguments
  • 3 ISO C++ standard 14882 4.2.1.
Categories: Uncategorized Tags: ,
Follow

Get every new post delivered to your Inbox.