I just encountered a case where I wanted to declare a C++ 20 concept deprecated. However it seems like my compiler (Apple Clang 14) does not accept adding a [[deprecated]] attribute to a concept. My attempt looked like
template <class T>
concept [[deprecated ("Some explanation")]] myConcept = someBoolCondition<T>;
Is deprecating concepts simply not supported (yet), did I choose a wrong syntax or is this a flaw of my compiler?
The possibility to add [[deprecated]] to a concept definition has been added only recently as a defect report with resolution of CWG 2428.
However, the attribute belongs after the concept's name, not before it:
template <class T>
concept myConcept [[deprecated ("Some explanation")]] = someBoolCondition<T>;
Your compiler is older than the resolution, so it can't have implemented it yet. It seems Clang hasn't implemented it yet at all, but future versions probably will.
GCC trunk does implement the DR, so the next GCC release (version 13), probably will as well.
Latest MSVC does not seem to implement it yet.
I haven't found a way to make make the attribute work directly on the concept but you can add it to the implementation:
template<class T>
struct someBoolCondition_impl {
// needed for clang/msvc:
[[deprecated ("Some explanation")]] static constexpr bool value = true;
};
template<class T>
// needed for gcc:
[[deprecated ("Some explanation")]]
inline constexpr bool someBoolCondition = someBoolCondition_impl<T>::value;
template <class T>
concept myConcept = someBoolCondition<T>;
Demo
Related
I work with template template parameters and want to construct new types based on template template parameters defined at another location. This sometimes works, but I think I miss something fundamentally, conceptually.
In the below minimal (I hope not too much distorted) example I expect the types of Example<GerericTemplate> and MakeAnotherX<Example<GenericTemplate>>::type to be identical, but they aren't always.
struct Something {};
template <template <typename> typename TemplateParameter>
struct Example {
template <typename T>
using InputTemplate = TemplateParameter<T>;
using FullType = TemplateParameter<Something>;
private:
FullType fData;
};
template <typename T>
struct GenericTemplate {};
// this works with (recent) GCC, but the static_assert below fails with clang
template <typename ExistingType,
template <typename> typename _InputTemplate
= ExistingType::template InputTemplate>
struct MakeAnother1 {
using type = Example<_InputTemplate>;
};
// this compiles, but static_assert below fails for both (recent) gcc and clang
template <typename ExistingType>
struct MakeAnother2 {
template <typename T> using _InputTemplate
= typename ExistingTemplate::template InputTemplate<T>;
using type = Example<_InputTemplate>;
};
#include <type_traits>
int main() {
using type1 = Example<GenericTemplate>;
static_assert(std::is_same<type1, MakeAnother1<type1>::type >::value, "this is not the same");
static_assert(std::is_same<type1, MakeAnother2<type1>::type >::value, "this is not the same");
return 0;
}
this example in godbolt
So far I am using gcc and clang (-std=c++17) for testing (and production), but in general I just wish to have standard compliant code. I really would like to be able to to reuse template template parameters in different context and classes as described in the minimal example above.
What is the correct way to achieve this in a robust manner? Also: is the fact that MakeAnother1 works with GCC a feature or a bug of GCC (and vice versa for clang)?
The "real code" is significantly more complex, so in particular I want those "Make" helper structs to work on new types.
Update
An earlier conceptually identical version of this question was asked about 6 years ago see old post. The news is that today this work on gcc version 5 and beyond but still no other compiler seems to support it. Unfortunately the discussion on CWG seems to have stalled on this point and could benefit from a reminder?
At this stage: after this update, if you prefer we can of course close this report here now. Thanks for all help!
As of the time of writing, cppreference gives a reasonably simple definition of the std::in_place_t family:
struct in_place_t {
explicit in_place_t() = default;
};
inline constexpr std::in_place_t in_place{};
template <class T>
struct in_place_type_t {
explicit in_place_type_t() = default;
};
template <class T>
inline constexpr std::in_place_type_t<T> in_place_type{};
template <size_t I> struct in_place_index_t {
explicit in_place_index_t() = default;
};
template <size_t I>
inline constexpr in_place_index_t<I> in_place_index{};
However, the latest draft of the C++17 standard linked from isocpp.org has a rather more complicated definition (section 20.2.7, page 536):
struct in_place_tag {
in_place_tag() = delete;
};
using in_place_t = in_place_tag(&)(unspecified );
template <class T>
using in_place_type_t = in_place_tag(&)(unspecified <T>);
template <size_t I>
using in_place_index_t = in_place_tag(&)(unspecified <I>);
in_place_tag in_place(unspecified );
template <class T>
in_place_tag in_place(unspecified <T>);
template <size_t I>
in_place_tag in_place(unspecified <I>);
The first version is simple and easy to understand, but second version is quite opaque to me. So, questions:
Which version is correct, post-Issaqua (November 2016)? (Presumably the second, but it's possible that N4606 hasn't yet been updated after the latest meeting and cppreference has.)
Clearly this has changed at some point in time; does anyone have a link to a paper mentioning the change?
Most importantly, can anyone explain how the second version is intended to work? What would a sample implementation look like?
The first version is the right one, currently, and will in all likelihood be the one ending up in C++17.
The second version was an attempt to allow one to write in_place everywhere, with nothing, with a type, or with an index:
std::optional<int> o(std::in_place, 1);
std::any a(std::in_place<int>, 1);
std::variant<int, int> v(std::in_place<0>, 1);
The only way to make this syntax work is to make in_place an overloaded function, and that also requires making in_place*_t aliases for references to functions. There's no real implementation difference otherwise - the in_place functions aren't meant to be called, they exist only so that a reference to them can be passed around as a tag and match the corresponding _t types.
Nonetheless it was too clever and caused its own problems (for instance, unlike plain tag types, they don't respond well to being decay'd, and plain std::in_place, being an overloaded function name, misbehaves with perfect forwarders: std::optional<std::optional<int>> o(std::in_place, std::in_place); doesn't work because the compiler can't resolve the second std::in_place), so it got backed out in Issaquah, and now you have to write
std::optional<int> o(std::in_place, 1);
std::any a(std::in_place_type<int>, 1);
std::variant<int, int> v(std::in_place_index<0>, 1);
A little less pretty, but more sane.
I'm trying to get a deeper understanding of C++ by reading the C++14 standard along with the source of libc++ and libstdc++. The implementation of various type_traits items varies between the two, particularly is_move_assignable, and I'm trying to figure out which of them is "more correct."
libc++:
template <class _Tp> struct is_move_assignable
: public is_assignable<typename add_lvalue_reference<_Tp>::type,
const typename add_rvalue_reference<_Tp>::type> {};
libstdc++:
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_move_assignable_impl;
template<typename _Tp>
struct __is_move_assignable_impl<_Tp, false>
: public false_type { };
template<typename _Tp>
struct __is_move_assignable_impl<_Tp, true>
: public is_assignable<_Tp&, _Tp&&>
{ };
template<typename _Tp>
struct is_move_assignable
: public __is_move_assignable_impl<_Tp>
{ };
The standard states:
For a referenceable type T, the same result as is_assignable<T&, T&&>::value, otherwise false.
The first thing I noted is that libc++ applies const to the second template parameter, which doesn't seem right since the move assignment operator takes a non-const rvalue. libstdc++ also uses __is_referenceable, which follows the wording of the standard, but libc++ doesn't. Is that requirement covered by libc++'s use of add_lvalue_reference and add_rvalue_reference, which both enforce __is_referenceable on their own?
I would really appreciate any insight into why each project chose their solutions!
Thanks! Any idea why the authors might have added const, then?
My best guess is temporary (hopefully) insanity:
https://github.com/llvm-mirror/libcxx/commit/6063ec176d5056683d6ddd310c2e3a8f1c7e1b46#diff-48f5ee43879b5ad38888f0a6ead10113R1245
;-)
I removed the const and ran the current unit tests and nothing failed.
For anything referenceable, the two implementations do the same thing, since the extraneous const in libc++ is meaningless but also harmless.
(Judging from the diff, it certainly looks like temporary insanity to me :) Seems to be a C&P issue from a (wrong) implementation of is_copy_assignable.)
For anything non-referenceable (i.e., cv void or abominable function types), libstdc++ returns false_type.
In libc++, add_{l,r}value_reference returns it unchanged (this depends on an issue resolution that postdates C++14). Sprinkling a const on top does nothing for AFTs and adds a const for the voidy types.
We then go to is_assignable, which SFINAE-tests the well-formedness of declval<T>() = declval<U>(), for either T == U == some AFT or T == some void type and U = some const-qualified void type. In all cases the expression is ill-formed (in a SFINAE-friendly manner), so we get false_type back.
The two are equivalent.
__is_referenceable is a non-standard, internal libstdc++ routine. (That doesn't mean it's bad, just that I wouldn't expect libc++ to use it). Also, the "is referenceable" concept came along much later than is_move_assignable.
The __is_referenceable helps when dealing with "abominable functions"; things like int (*) (double) &&.
Looks like I need to write more tests :-)
I was very surprised today to discover that Intel's icpc (version 14.0.2, using std=c++0x) fails to compile the following snippet.
#include <type_traits>
namespace traits_tests {
template<typename>
struct sfinae_true : std::true_type {};
template<typename T>
static auto value_type(int) -> sfinae_true<typename T::value_type>;
template<typename T>
static auto value_type(void*) -> std::false_type;
}
template<typename C>
struct has_value_type
: decltype(traits_tests::value_type<C>(0)) {};
complaining about the last line:
inc/traits.h(258): error: expected an identifier
: decltype(traits_tests::value_type<C>(0)) {};
^
The code works fine with clang and gcc.
I don't really fancy a complete re-write to make it work with flawed compilers (why is that always the commercial compilers are flawed?).
Is there a simpler way, than a completely different SFINAE pattern, to make it work with icc?
EDIT: Yes, I know that icc supports decltype since some time. But in the particular context above, icc fails to support it. Also note that using std=c++11 instead of std=c++0x makes no difference.
As stated in the question, and comments, decltype has been supported in iccfor some time now; the problem is that it's not usable in every context because of a nasty bug in the compiler.
More specifically it cannot be used directly when specifying the base of a class, which requires us to write a workaround..
If we can't use it directly, let's use it indirectly (through an alias template)!
EXAMPLE WORKAROUND
template<class T>
using identity_hack = T;
template<typename C>
struct has_value_type
: identity_hack<decltype (traits_tests::value_type<C> (0))>
{ }
Note: There are many variations to the above, one could for example use std::enable_if<true, decltype (...)>::type as an alternative if one doesn't want to declare something of their own.
You can use a template based workaround - any of the standard types that take a template type argument and expose it as a typedef, then wrap that in a macro that's only defined for ICC e.g.
#ifdef __INTEL_COMPILER
#include <utility>
#define decltype(...) \
std::pair<decltype(__VA_ARGS__), int>::first_type
#endif
Which allows your example to compile without changes.
Once the bug is fixed in all versions of ICC you're using you can remove the macro definition without changing any other code.
(See this answer to a similar MSVC issue)
This is more of a c++ standards question.
Consider the following code:
template <typename T>
class has_Data
{
typedef char one;
typedef long two;
template <typename C> static one test( typeof(&C::Data) ) ;
template <typename C> static two test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
class MyClass {
private:
struct Data {
};
};
void function(bool val = has_Data<MyClass>::value) {}
The above code works with gcc (GCC) 4.4.3
However with clang version 3.3 (2545b1d99942080bac4a74cda92c620123d0d6e9) (2ff97832e593926ea8dbdd5fc5bcf367475638a9)
it gives this error:
test_private_data.cpp:7:54: error: 'Data' is a private member of 'MyClass'
template <typename C> static one test( typeof(&C::Data) ) ;
^
/devshared/home/rhanda/test_private_data.cpp:7:37: note: while substituting explicitly-specified template arguments into function template 'test'
template <typename C> static one test( typeof(&C::Data) ) ;
^
/devshared/home/rhanda/test_private_data.cpp:21:26: note: in instantiation of template class 'has_Data<MyClass>' requested here
void function(bool val = has_Data<MyClass>::value) {}
^
1 error generated.
Which one is right?
From standard document (n3485), I found a statement which seems to agree with clang more than gcc.
Access control is applied uniformly to all names, whether the names are referred to from declarations or expressions.
I would assume that GCC is right.
The first thing to note is that no non-friend code should be able to positively report the existence of a given private member. So if that is what you try to do, you have to modify your design. A class can do anything with its private members, and other code (excepting friends) should have no way to know about it. That's by design.
However, there is the SFINAE principle: substitution failure is not an error. Since MyClass::Data is private, the code in has_Data should – in my opinion – act as if there was no C::Data member at all. Hence the first function would lead to a substitution failure, which gets silently ignored, and the second function is the one used. Adding a bit more code, my GCC 4.7.2 compiles this without issues and with has_Data<MyClass>::value evaluating to false. Correct SFINAE in my opinion.
Trying to back this opinion up with a quotation from the document you referred to, I found the following in section 14.8.2 paragraph 8:
Note: Access checking is done as part of the substitution process.
This is a non-normative note in the standard, but to me appears to be a very readable and clear indication that SFINAE should in fact apply in this situation, just the way GCC handles it.
Edit: As #hvd pointed out in a comment, the above is only true for C++11. In older versions of the standard, the situation used to be different. Issue 1170: Access checking during template argument deduction has details on that change.
GCC will not compile this code with -std=c++03 or -std=c++11 due to the fact that typeof is a GNU extension. The fact that -std=gnu++03 still compiles the code might perhaps be considered inappropriate, but since the way forward is using the C++11 semantics, I wouldn't bother filing a report about this.