Note that there are some explanatory texts on larger screens.

plurals
  1. POis_convertible for multiple arguments
    primarykey
    data
    text
    <p>Suppose I don't have <code>std::is_convertible</code> for whatever reason and want to implement it myself. The standard says something along these lines:</p> <blockquote> <p>The predicate condition for a template specialization <code>is_convertible&lt;From, To&gt;</code> shall be satisfied if and only if the return expression in the following code would be well-formed, including any implicit conversions to the return type of the function:</p> <pre><code>To f() { return declval&lt;From&gt;(); } </code></pre> </blockquote> <p>Okay, no big deal, I can do it like this (Note argument order opposite to the one in <code>std::is_convertible</code>, this is intentional and irrelevant to the issue):</p> <pre><code>template &lt;typename To_, typename From_&gt; class my_is_convertible { private: template &lt;typename To&gt; struct indirector { indirector(To); }; template &lt;typename To, typename From&gt; struct tag {}; template &lt;typename To, typename From&gt; static auto test(tag&lt;To, From&gt;) -&gt; decltype(indirector&lt;To&gt;(std::declval&lt;From&gt;()), std::true_type()); static auto test(...) -&gt; std::false_type; public: static constexpr bool value = decltype(test(tag&lt;To_, From_&gt;()))::value; }; </code></pre> <p>This seems to work as intended, and as far as I can tell does the same thing.</p> <p>Now I can distinguish between implicit and explicit (or none at all) constructors:</p> <pre><code>struct A {}; struct B {}; struct Test { Test(A); explicit Test(B); }; int main() { std::cout &lt;&lt; my_is_convertible&lt;Test, A&gt;::value; // true std::cout &lt;&lt; my_is_convertible&lt;Test, B&gt;::value; // false return 0; } </code></pre> <p>So far, so good. Now, I want to do the same with multiple argument constructors. This didn't make sense prior to <code>c++11</code> as there was no way to call multiargument constructor implicitly. But now we have brace enclosed initializer list syntax, and <code>explicit</code> keyword on multiargument constructor makes a difference.</p> <p>Let us extend the definition:</p> <blockquote> <p>The predicate condition for a template specialization <code>my_is_convertible_many&lt;To, From...&gt;</code> shall be satisfied if and only if the return expression in the following code would be well-formed, including any implicit conversions to the return type of the function:</p> <pre><code>To f() { return {declval&lt;From&gt;()...}; } </code></pre> </blockquote> <p>To implement it I went the obvious way:</p> <pre><code>template &lt;typename To_, typename... From_&gt; class my_is_convertible_many { private: template &lt;typename To&gt; struct indirector { indirector(To); }; template &lt;typename To, typename... From&gt; struct tag {}; template &lt;typename To, typename... From&gt; static auto test(tag&lt;To, From...&gt;) -&gt; decltype(indirector&lt;To&gt;({std::declval&lt;From&gt;()...}), std::true_type()); static auto test(...) -&gt; std::false_type; public: static constexpr bool value = decltype(test(tag&lt;To_, From_...&gt;()))::value; }; </code></pre> <p>This correctly reports <code>true</code> in the presence of matching implicit constructor and <code>false</code> if the is no matcing constructor. But it fails to compile if there is an explicit matching constructor (at least on gcc 4.8.1):</p> <pre><code>struct A {}; struct B {}; struct C {}; struct Test { Test(A, A); //Test(B, B); explicit Test(C, C); }; int main() { std::cout &lt;&lt; my_is_convertible_many&lt;Test, A, A&gt;::value; // true, correct std::cout &lt;&lt; my_is_convertible_many&lt;Test, B, B&gt;::value; // false, correct std::cout &lt;&lt; my_is_convertible_many&lt;Test, C, C&gt;::value; // error return 0; } </code></pre> <p>The error is about attempting to implicitly call explicit constructor, which on gcc sounds like this:</p> <pre><code>main.cpp: In substitution of 'template&lt;class To, class ... From&gt; static decltype (((my_is_convertible_many&lt;To_, From_&gt;::indirector&lt;To&gt;)({(declval&lt;From&gt;)()...}), std::true_type())) my_is_convertible_many&lt;To_, From_&gt;::test(my_is_convertible_many&lt;To_, From_&gt;::tag&lt;To, From ...&gt;) [with To = To; From = {From ...}; To_ = Test; From_ = {C, C}] [with To = Test; From = {C, C}]': main.cpp:21:73: required from 'constexpr const bool my_is_convertible_many&lt;Test, C, C&gt;::value' main.cpp:37:54: required from here main.cpp:17:97: error: converting to 'Test' from initializer list would use explicit constructor 'Test::Test(C, C)' static auto test(tag&lt;To, From...&gt;) -&gt; decltype(indirector&lt;To&gt;({std::declval&lt;From&gt;()...}), std::true_type()); ^ </code></pre> <p>Which is sensible. I, however, expect this overload of <code>test</code> to sfinae out and the other one to be used instead, thus producing no error.</p> <p>So the question is: Why doesn't this happen, and what can I do about it?</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload