We consider the goal of creating two different types, using the exact same syntax. This can be easily done with lambdas:
auto x = []{}; auto y = []{}; static_assert(!std::is_same_v<decltype(x), decltype(y)>);
But instead of using lambdas, we are looking for another, more elegant syntax. Here are some tests. We start by defining some tools:
#include <iostream> #include <type_traits> #define macro object<decltype([]{})> #define singleton object<decltype([]{})> constexpr auto function() noexcept { return []{}; } template <class T = decltype([]{})> constexpr auto defaulted(T arg = {}) noexcept { return arg; } template <class T = decltype([]{})> struct object { constexpr object() noexcept {} }; template <class T> struct ctad { template <class... Args> constexpr ctad(const Args&...) noexcept {} }; template <class... Args> ctad(const Args&...) -> ctad<decltype([]{})>;
and the following variables:
// Lambdas constexpr auto x0 = []{}; constexpr auto y0 = []{}; constexpr bool ok0 = !std::is_same_v<decltype(x0), decltype(y0)>; // Function constexpr auto x1 = function(); constexpr auto y1 = function(); constexpr bool ok1 = !std::is_same_v<decltype(x1), decltype(y1)>; // Defaulted constexpr auto x2 = defaulted(); constexpr auto y2 = defaulted(); constexpr bool ok2 = !std::is_same_v<decltype(x2), decltype(y2)>; // Object constexpr auto x3 = object(); constexpr auto y3 = object(); constexpr bool ok3 = !std::is_same_v<decltype(x3), decltype(y3)>; // Ctad constexpr auto x4 = ctad(); constexpr auto y4 = ctad(); constexpr bool ok4 = !std::is_same_v<decltype(x4), decltype(y4)>; // Macro constexpr auto x5 = macro(); constexpr auto y5 = macro(); constexpr bool ok5 = !std::is_same_v<decltype(x5), decltype(y5)>; // Singleton constexpr singleton x6; constexpr singleton y6; constexpr bool ok6 = !std::is_same_v<decltype(x6), decltype(y6)>;
and the following test:
int main(int argc, char* argv[]) { // Assertions static_assert(ok0); // lambdas //static_assert(ok1); // function static_assert(ok2); // defaulted function static_assert(ok3); // defaulted class //static_assert(ok4); // CTAD static_assert(ok5); // macro static_assert(ok6); // singleton (macro also) // Display std::cout << ok1 << std::endl; std::cout << ok2 << std::endl; std::cout << ok3 << std::endl; std::cout << ok4 << std::endl; std::cout << ok5 << std::endl; std::cout << ok6 << std::endl; // Return return 0; }
this is compiled with the current trunk version of GCC, with options -std=c++2a
. See result here in compiler explorer.
The fact that ok0
, ok5
and ok6
work are not really a surprise. However, the fact that ok2
and ok3
are true
while ok4
is not is very surprising to me.
ok3
true
but ok4
false
?Note: I really hope this is a feature and not a bug, but just because it makes some crazy ideas implementable
You cannot give default arguments to the same template parameters in different declarations in the same scope. The compiler will not allow the following example: template<class T = char> class X; template<class T = char> class X { };
A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)
Can default arguments be used with the template class? Explanation: The template class can use default arguments.
The default template defines the network settings used when claiming a gateway. There is a different default gateway for each model. You can: Change a gateway model's default template settings. Use Claim Policies to define a custom default template based on the device's custom field definition.
Could someone provide an explanation of the rules that make ok3 true but ok4 false?
ok3 is true because uses lambdas type as default type.
The type of a lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type,
Hence, default template type for object
, template parameter type for macro
and singltone
always different after every instatiation. But, for function function
call returned lambda is unique and its type is unique. Template function ctad
has template only for parameters but return value is unique. If rewrite function as:
template <class... Args, class T = decltype([]{})> ctad(const Args&...) -> ctad<T>;
In this case return type will be defferent after every instantiation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With