Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8820919
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 14, 20262026-06-14T05:43:36+00:00 2026-06-14T05:43:36+00:00

Synopsis Given a type with a variadic template constructor that forwards the arguments to

  • 0

Synopsis

Given a type with a variadic template constructor that forwards the arguments to an implementation class, is it possible to restrict the types being forwarded with SFINAE?

Details

First, consider the non-variadic case with a constructor taking a universal reference. Here one can disable forwarding of a non-const lvalue reference via SFINAE to use the copy constructor instead.

struct foo
{
  foo() = default;
  
  foo(foo const&) 
  {
      std::cout << "copy" << std::endl;
  }

  template <
    typename T,
    typename Dummy = typename std::enable_if<
      !std::is_same<
          T,
          typename std::add_lvalue_reference<foo>::type
      >::value
    >::type
  >
  foo(T&& x)
    : impl(std::forward<T>(x))
  {
      std::cout << "uref" << std::endl;
  }

  foo_impl impl;
};

This restriction of the universal reference is useful because otherwise the implementation class would receive a non-const lvalue reference of type foo, which it does not know about.
Full example at LWS.

Question

But how does this work with variadic templates? Is it possible at all? If so, how? The naive extension does not work:

template <
  typename... Args,
  typename Dummy = typename std::enable_if<
    !std::is_same<
        Args...,
        typename std::add_lvalue_reference<foo>::type
    >::value
  >::type
>
foo(Args&&... args)
  : impl(std::forward<Args>(args)...)
{
    std::cout << "uref" << std::endl;
}

(Also at LWS.)

EDIT: I found that R. Martinho Fernandez blogged about a variation of this issue in 2012: Link

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-14T05:43:38+00:00Added an answer on June 14, 2026 at 5:43 am

    Here are the different ways to write a properly constrained constructor template, in increasing order of complexity and corresponding increasing order of feature-richness and decreasing order of number of gotchas.

    This particular form of EnableIf will be used but this is an implementation detail that doesn’t change the essence of the techniques that are outlined here. It’s also assumed that there are And and Not aliases to combine different metacomputations. E.g. And<std::is_integral<T>, Not<is_const<T>>> is more convenient than std::integral_constant<bool, std::is_integral<T>::value && !is_const<T>::value>.

    I don’t recommend any particular strategy, because any constraint is much, much better than no constraint at all when it comes to constructor templates. If possible, avoid the first two techniques which have very obvious drawbacks — the rest are elaborations on the same theme.

    Constrain on self

    template<typename T>
    using Unqualified = typename std::remove_cv<
        typename std::remove_reference<T>::type
    >::type;
    
    struct foo {
        template<
            typename... Args
            , EnableIf<
                Not<std::is_same<foo, Unqualified<Args>>...>
            >...
        >
        foo(Args&&... args);
    };
    

    Benefit: avoids the constructor from participating in overload resolution in the following scenario:

    foo f;
    foo g = f; // typical copy constructor taking foo const& is not preferred!
    

    Drawback: participates in every other kind of overload resolution

    Constrain on construction expression

    Since the constructor has the moral effects of constructing a foo_impl from Args, it seems natural to express the constraints on those exact terms:

        template<
            typename... Args
            , EnableIf<
                std::is_constructible<foo_impl, Args...>
            >...
        >
        foo(Args&&... args);
    

    Benefit: This is now officially a constrained template, since it only participates in overload resolution if some semantic condition is met.

    Drawback: Is the following valid?

    // function declaration
    void fun(foo f);
    fun(42);
    

    If, for instance, foo_impl is std::vector<double>, then yes, the code is valid. Because std::vector<double> v(42); is a valid way to construct a vector of such type, then it is valid to convert from int to foo. In other words, std::is_convertible<T, foo>::value == std::is_constructible<foo_impl, T>::value, putting aside the matter of other constructors for foo (mind the swapped order of parameters — it is unfortunate).

    Constrain on construction expression, explicitly

    Naturally, the following comes immediately to mind:

        template<
            typename... Args
            , EnableIf<
                std::is_constructible<foo_impl, Args...>
            >...
        >
        explicit foo(Args&&... args);
    

    A second attempt that marks the constructor explicit.

    Benefit: Avoids the above drawback! And it doesn’t take much either — as long as you don’t forget that explicit.

    Drawbacks: If foo_impl is std::string, then the following may be inconvenient:

    void fun(foo f);
    // No:
    // fun("hello");
    fun(foo { "hello" });
    

    It depends on whether foo is for instance meant to be a thin wrapper around foo_impl. Here is what I think is a more annoying drawback, assuming foo_impl is std::pair<int, double*>.

    foo make_foo()
    {
        // No:
        // return { 42, nullptr };
        return foo { 42, nullptr };
    }
    

    I don’t feel like explicit actually saves me from anything here: there are two arguments in the braces so it’s obviously not a conversion, and the type foo already appears in the signature, so I’d like to spare with it when I feel it is redundant. std::tuple suffers from that problem (although factories like std::make_tuple do ease that pain a bit).

    Separately constrain conversion from construction

    Let’s separately express construction and conversion constraints:

    // New trait that describes e.g.
    // []() -> T { return { std::declval<Args>()... }; }
    template<typename T, typename... Args>
    struct is_perfectly_convertible_from: std::is_constructible<T, Args...> {};
    
    template<typename T, typename U>
    struct is_perfectly_convertible_from: std::is_convertible<U, T> {};
    
    // New constructible trait that will take care that as a constraint it
    // doesn't overlap with the trait above for the purposes of SFINAE
    template<typename T, typename U>
    struct is_perfectly_constructible
    : And<
        std::is_constructible<T, U>
        , Not<std::is_convertible<U, T>>
    > {};
    

    Usage:

    struct foo {
        // General constructor
        template<
            typename... Args
            , EnableIf< is_perfectly_convertible_from<foo_impl, Args...> >...
        >
        foo(Args&&... args);
    
        // Special unary, non-convertible case
        template<
            typename Arg
            , EnableIf< is_perfectly_constructible<foo_impl, Arg> >...
        >
        explicit foo(Arg&& arg);
    };
    

    Benefit: Construction and conversion of foo_impl are now necessary and sufficient conditions for construction and conversion of foo. That is to say, std::is_convertible<T, foo>::value == std::is_convertible<T, foo_impl>::value and std::is_constructible<foo, Ts...>::value == std::is_constructible<foo_impl, T>::value both hold (almost).

    Drawback? foo f { 0, 1, 2, 3, 4 }; doesn’t work if foo_impl is e.g. std::vector<int>, because the constraint is in terms of a construction of the style std::vector<int> v(0, 1, 2, 3, 4);. It is possible to add a further overload taking std::initializer_list<T> that is constrained on std::is_convertible<std::initializer_list<T>, foo_impl> (left as an exercise to the reader), or even an overload taking std::initializer_list<T>, Ts&&... (constraint also left as an exercise to the reader — but remember that ‘conversion’ from more than one argument is not a construction!). Note that we don’t need to modify is_perfectly_convertible_from to avoid overlap.

    The more obsequious amongst us will also make sure to discriminate narrow conversions against the other kind of conversions.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Question Synopsis Given a std::vector<T> , how can I create a view that exposes
Synopsis How can I safely design a move constructor when a class uses multiple
The SYNOPSIS for Test::DBIx::Class states: Yes, it looks like a lot of boilerplate, but
Synopsis : When calling an executable that links to shared libraries from Java code
A brief synopsis of the situation: I have a service that takes information in
Synopsis I've got a query with a WHERE clause that contains a condition that
Suggestions other that dumping IE6 that is... I can't control that :) Quick synopsis
Synopsis: I am developing a HTML5 web app that will allow tablets(iPad or Droid)
A = imread(filename, fmt) [X, map] = imread(...) The above is in the synopsis
Synopsis: Each User account has a UserProfile to hold extended info like phone numbers,

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.