looking at std::ref and std::cref, the way I think it works is having two prototypes
template< class T >
std::reference_wrapper<const T> cref( const T& t ) noexcept;
template< class T >
void cref( const T&& ) = delete;
and the T&&
template function is deleted.
But when I imitate this with a similar variadic template function, the compilation is successful if atleast one argument satisfies the condition. So now I don't understand how or why this (does not?) works.
template<typename ... Ts>
void foo(const Ts& ... ts) { }
template<typename ... Ts>
void foo(const Ts&& ...) = delete;
int main(){
std::string a{"sss"};
foo<std::string>(a);
//foo<std::string>("sss"); error, deleted foo
foo<std::string, std::string>(a, "sss"); // I was expecting error here
//foo<std::string, std::string>("aaaa", "sss"); error, deleted foo
foo<std::string, std::string, std::string>(a, "aaa", "sss"); // I was expecting error here
}
This seems to be the case with clang, gcc and also msvc https://godbolt.org/z/8cboT48En
CodePudding user response:
You can check std::is_lvalue_reference for this purpose.
template<typename ... Ts, std::enable_if_t<(!std::is_lvalue_reference<Ts>::value && ...), int> = 0>
void foo(const Ts& ... ts) {}
Then all of calling function like this is error.
foo<std::string>("sss"); //error, deleted foo
foo<std::string, std::string>(a, "sss"); // I was expecting error here
foo<std::string, std::string>("aaaa", "sss"); error, deleted foo
foo<std::string, std::string, std::string>(a, "aaa", "sss"); // I was expecting error here
CodePudding user response:
So now I don't understand how or why this (does not?) works.
Contrary to reference wrapper code, your overload takes reference to const: temporaries can bind to.
If you remove the const
, you have expected error:
template<typename ... Ts> void foo(Ts& ... ts) { /*..*/ }
template<typename ... Ts> void foo(const Ts&& ...) = delete;
CodePudding user response:
Ordinary string literals are lvalues, so your test isn't testing what you want. Testing with literals that are rvalues, I found you need to have each variant of cv-ref qualifiers.
#include<iostream>
#include<utility>
#include<string>
template<typename ... Ts>
void foo(const Ts& ... ts) { }
template<typename ... Ts>
void foo(Ts& ... ts) { foo(std::as_const(ts)...); }
template<typename ... Ts>
void foo(const Ts&& ...) = delete;
template<typename ... Ts>
void foo(Ts&& ...) = delete;
using namespace std::string_literals;
int main(){
std::string a{"sss"};
foo(a);
// errors, as desired
// foo("sss"s);
// foo(a, "sss"s);
// foo("aaaa"s, "sss"s);
// foo(a, "aaa"s, "sss"s);
}