Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is P0522R0 breaking code?

Today I was reading the C++17 support page of clang. I've notice something odd. The feature Matching template template parameters to compatible arguments (P0522R0) is marked as partial, because it must be activate through a switch. Their note says:

Despite being the the resolution to a Defect Report, this feature is disabled by default in all language versions, and can be enabled explicitly with the flag -frelaxed-template-template-args in Clang 4. The change to the standard lacks a corresponding change for template partial ordering, resulting in ambiguity errors for reasonable and previously-valid code. This issue is expected to be rectified soon.

What kind of constructs breaks when this feature is activated? Why can it break code and how?

like image 304
Guillaume Racicot Avatar asked Nov 14 '17 18:11

Guillaume Racicot


2 Answers

You can have code like this:

template<template<typename> typename>
struct Foo {};

template<typename, typename = void>
struct Bar {};

Foo<Bar> unused;

Without the defect resolution, unused would be ill-formed, because foo takes a template with only one template parameter, and not two. If you relied on this (maybe for SFINAE):

template<template<typename> typename>
void foo();

template<template<typename, typename> typename>
void foo();

template<typename, typename = void>
struct Bar {};

int main() {
    foo<Bar>(); // ambiguous after resolution!
}

Then the call would fail! The problem is that there was no corresponding change to partial ordering, and so both candidate functions have the same viability, and the call is ambiguous.

like image 113
Rakete1111 Avatar answered Oct 27 '22 23:10

Rakete1111


A more common scenario is when some code wants to inspect the template arguments with a set of partial specializations, e.g.:

template<class> struct Foo;

template<template<class> class X, class T> 
struct Foo<X<T>> { /* ... */ };

template<template<class, class> class X, class T, class U> 
struct Foo<X<T, U>> { /* ... */ };

// etc., etc.

Foo<std::vector<int>> is now ill-formed without an appropriate partial ordering fix.

like image 7
T.C. Avatar answered Oct 27 '22 23:10

T.C.