
#include <iostream>
#include <typeinfo>

int* returnsPointer() { return nullptr; }
int& returnsRef()     { static int a; return a; }
int  returnsValue()   { return 10; }

template<typename> void printType();
template<> void printType<int>()
{
	std::cout << "int\n";
}

template<> void printType<int*>()
{
	std::cout << "int*\n";
}

template<> void printType<int&>()
{
	std::cout << "int&\n";
}

int main()
{
	// similar D behavior in C++:
	
	auto d_pointer = returnsPointer();
	auto d_ref     = returnsRef();
	auto d_ref2    = &returnsRef();
	auto d_value   = returnsValue();
	
	printType<decltype(d_pointer)>();
	printType<decltype(d_ref)>();
	printType<decltype(d_ref2)>();
	printType<decltype(d_value)>();
	
	std::cout << "--------------------\n";
	
	// desired C++ behavior to have in D:
	
	auto* c_pointer = returnsPointer();
	// auto* c_ref     = returnsRef();    // error can't compile this (desired behavior here)
	auto* c_ref2    = &returnsRef();
	// auto* c_value   = returnsValue(); // error can't compile this
	
	printType<decltype(c_pointer)>();
	printType<decltype(c_ref2)>();

}