专门的问题变量模板函数 [英] Problems specializing variable template function

查看:141
本文介绍了专门的问题变量模板函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了一个函数inListi(),它接受至少一个参数,并将第一个参数与所有后续参数的列表进行比较。如果第一个参数==列表中的元素,则返回true,否则返回false。所以:

  if(inListi(1.2,2.3,4.5,1.2))
std :: cout< ; 返回true,因为最后一个参数等于第一个参数。 << endl

if(inListi(hello,world,HEllo))
std :: cout< 这应该打印出来,因为最后一个参数。 << endl

问题是,它不工作。我有下面的代码。对于char [N],在继续之前,我将
数组的N个部分复制到字符串中。我想这样做,因为我可能传递一个不是null终止的char [N]。



无论如何,代码如下。大多数代码是多余的,并且处理const和一个参数的组合是const [N],另一个不是那个类型。 (顺便说一句,有没有办法减少这种重复?)

  #include< iostream> 
#include< stdexcept>
#include< string>
#include< sstream>
#include< typeinfo>
#include< type_traits>

#include< boost / algorithm / string.hpp>

using namespace std;

////////////////////////////////////////// ////////////////////////////////////////
// inListi
/ ////////////////////////////////////////////////// /////////////////////////////
模板< typename T>
bool inListi(T&& value)
{
return false;
}


template< typename FirstType,typename SecondType,typename ... Rest>
bool inListi(FirstType& first,SecondType&& amp; second,Rest ... rest)
{
cout< GENERIC inListi< endl
cout<< 第一是< typeid(first).name()<< endl
cout<< 第二是< typeid(second).name()<< endl

if(first == second)
return true;
else return inListi(first,rest ...);
}


//我们专门用于字符串的inListi。我们减少了。
//但是如果char [n]被传递了呢?我们有专门化,
//将它转换为字符串。
template< typename ... Rest>
bool inListi(string&& first,string&& amp; second,Rest ... rest){
string lFirst = first;
string lSecond = second;

cout<< LOWERED<< endl

boost :: algorithm :: to_lower(lFirst);
boost :: algorithm :: to_lower(lSecond);

if(lFirst == lSecond)
return true;
else return inListi(first,rest ...);
}



//当我们给出char数组时的特殊化。我们将
//数组复制到数组大小的字符串中。这是做的
//来处理的情况下的字符数组不是nul终止。
//重复的数量是对哪个参数是一个字符数组
//进行置换,以及对const常数。
template< int F,typename SecondType,typename ... Rest>
bool inListi(char(& amp; first)[F],SecondType&&&  Rest ... rest){
string strFirst = string(first,F);
cout<< arr,type,rest< endl
return inListi(strFirst,second,rest ...);
}
template< int F,typename SecondType,typename ... Rest>
bool inListi(con​​st char(& amp; first)[F],SecondType&&&  Rest ... rest){
string strFirst = string(first,F);
cout<< const arr,type,rest< endl
return inListi(strFirst,second,rest ...);
}
template< typename FirstType,int S,typename ... Rest>
bool inListi(FirstType& first,char(& amp; second)[S],Rest ... rest){
string strSecond = string(second,S);
cout<< type,arr,rest< endl
return inListi(first,strSecond,rest ...);
}
template< typename FirstType,int S,typename ... Rest>
bool inListi(FirstType& first,const char(& amp; second)[S],Rest ... rest){
string strSecond = string(second,S);
cout<< type,const arr,rest< endl
return inListi(first,strSecond,rest ...);
}
template< int F,int S,typename ... Rest>
bool inListi(char(& first)[F],char(& amp; second)[S],Rest ... rest){
string strFirst = string );
string strSecond = string(second,S);
cout<< arr,arr,rest< endl
return inListi(strFirst,strSecond,rest ...);
}
template< int F,int S,typename ... Rest>
bool inListi(con​​st char(& first)[F],char(& amp; second)[S],Rest ... rest){
string strFirst = string F);
string strSecond = string(second,S);
cout<< const arr,arr,rest< endl
return inListi(strFirst,strSecond,rest ...);
}
template< int F,int S,typename ... Rest>
bool inListi(char(& first)[F],const char(& amp; second)[S],Rest ... rest){
string strFirst = string F);
string strSecond = string(second,S);
cout<< arr,const arr,rest< endl
return inListi(strFirst,strSecond,rest ...);
}
template< int F,int S,typename ... Rest>
bool inListi(con​​st char(& first)[F],const char(& amp; second)[S],Rest ... rest){
string strFirst = string , F);
string strSecond = string(second,S);
cout<< const arr,const arr,rest< endl
return inListi(strFirst,strSecond,rest ...);
}


int main(){

if(inListi(Hello,World,HEllo))
cout < 你好在listi。 << endl
else
cout<< 你不是在listi。 << endl

return 0;
}

程序的输出如下:

  [bitdiot foo] $ g ++ forStackOverflow.cpp -std = gnu ++ 0x 
[bitdiot foo] $ ./a.out
GENERIC inListi
第一个是A6_c
第二个是A6_c
GENERIC inListi
第一个是A6_c
第二个是PKc
你不是在listi中。

注意,没有中间代码被调用,它直接使用通用版本。另外,看起来很奇怪的另一件事是PKc。我假设是char *型。

解决方案



看起来你可以使用 const char * 的重载(这也许是 PKc 是指)。



可能类似:

  template< typename ... Rest> ; 
bool inListi(con​​st char * first,const char * second,Rest ... rest){
cout< const char *,const char *,rest< endl
return inListi(string(first),string(second),rest ...);
}

其他两件事:




  • 请注意使用临时值,以便我们调用 string&&& 版本

  • a const char * 重载将匹配第一个调用,但您可能需要更多的重载来处理后续调用






另一个编辑:对防止参数包扩展中的数组衰减向我们展示了如何通过在参数包中使用右值引用来实现这一点:

  #include< iostream> 
#include< string>
#include< utility>
#include< algorithm>
#include< cctype>

template< typename T>
bool inListi(T&& value)
{
return false;
}

template< typename FirstType,typename SecondType,typename ... Rest>
bool inListi(FirstType& amp; first,SecondType&&& amp; first,Rest& ... rest)
{
if(first == second)
return true ;
else
return inListi(std :: forward< FirstType&&>(first),rest ...);
}

template< int N,int M,typename ... Rest>
bool inListi(char(& first)[N],char(& second)[M],Rest& ... rest)
{
std :: string lFirst (第一,N);
std :: transform(lFirst.begin(),lFirst.end(),lFirst.begin(),:: tolower);
std :: string lSecond(second,M);
std :: transform(lSecond.begin(),lSecond.end(),lSecond.begin(),:: tolower);

if(lFirst == lSecond)
return true;
else
return inListi(first,rest ...);
}

template< typename ... Rest>
bool inListi(con​​st char * first,const char * second,Rest& ... rest)
{
std :: string lFirst(first);
std :: transform(lFirst.begin(),lFirst.end(),lFirst.begin(),:: tolower);
std :: string lSecond(second);
std :: transform(lSecond.begin(),lSecond.end(),lSecond.begin(),:: tolower);

if(lFirst == lSecond)
return true;
else
return inListi(first,rest ...);
}

int main(){
char a [5] = {'H','e','l','l','o'
char b [5] = {'W','o','r','l','d'};
char c [5] = {'H','E','l','l','o'};
std :: cout<< inListi(a,b,c)<< '\\\
';
std :: cout<< inListi(Hello,World,HEllo)< '\\\
';
std :: cout<< inListi(5,42,5)<< '\\\
';
}

只要所有参数都具有相同的类型,强>。如果你想开始混合类型,你可能需要开始写所有适当的重载对。


I am writing a function inListi() which takes at least one argument and compares the first argument to thes list of all subsequent arguments. returns true if first argument == an element in the list, otherwise false. So:

if( inListi( 1.2, 2.3, 4.5, 1.2))
  std::cout << "Returns true because last argument equals the first argument." << endl;

if( inListi( "hello", "world", "HEllo"))
    std::cout << "This should print out because of the last argument." << endl;

Problem is, it doesn't work. I have the code below. For char[N], I copy N portions of the array into a string before continuing. I want to do this, because I might be passed a char[N] that is not null terminated.

Anyways, the code is below. Most of the code is redundant and deal with const and combinations of one argument being const[N] and the other not of that type. (By the way, is there a way to reduce this repetition?)

#include <iostream>
#include <stdexcept>
#include <string>
#include <sstream>
#include <typeinfo>
#include <type_traits>

#include <boost/algorithm/string.hpp>

using namespace std;

////////////////////////////////////////////////////////////////////////////////
// inListi
////////////////////////////////////////////////////////////////////////////////
template<typename T>
bool inListi(T&& value)
{
    return false;
}


template<typename FirstType, typename SecondType, typename ... Rest>
bool inListi(FirstType&& first, SecondType&& second, Rest ... rest)
{
    cout << "GENERIC inListi" << endl;
    cout << "first is " << typeid(first).name() << endl;
    cout << "second is " << typeid(second).name() << endl;

    if( first == second)
        return true;
    else return inListi( first, rest...);
}


// We specialize the inListi for strings.  We lower the case.
// but what if char[n] is passed?  We have specializations that
// convert that to strings.
template<typename ... Rest>
bool inListi( string &&first, string &&second,  Rest ... rest) {
    string lFirst = first;
    string lSecond = second;

    cout << "LOWERED" << endl;

    boost::algorithm::to_lower( lFirst);
    boost::algorithm::to_lower( lSecond);

    if( lFirst == lSecond)
        return true;
    else return inListi( first, rest...);
}



// Specializations for when we are given char-arrays.  We copy the
// the arrays into a string upto the size of the array.  This is done
// to take care of the case of when the char-array is not nul-terminated.
// The amount repetition is to permutate over which argument is a char-array
// and also for const-ness.
template<int F, typename SecondType, typename ... Rest>
bool inListi( char (&&first)[F], SecondType &&second, Rest ... rest) {
    string strFirst = string( first, F);
    cout << "arr, type, rest" << endl;
    return inListi( strFirst, second, rest...);
}
template<int F, typename SecondType, typename ... Rest>
bool inListi( const char (&&first)[F], SecondType &&second, Rest ... rest) {
    string strFirst = string( first, F);
    cout << "const arr, type, rest" << endl;
    return inListi( strFirst, second, rest...);
}
template<typename FirstType, int S, typename ... Rest>
bool inListi( FirstType &&first, char (&&second)[S], Rest ... rest) {
    string strSecond = string( second, S);
    cout << "type, arr, rest" << endl;
    return inListi( first, strSecond, rest...);
}
template<typename FirstType, int S, typename ... Rest>
bool inListi( FirstType &&first, const char (&&second)[S], Rest ... rest) {
    string strSecond = string( second, S);
    cout << "type, const arr, rest" << endl;
    return inListi( first, strSecond, rest...);
}
template<int F, int S, typename ... Rest>
bool inListi( char (&&first)[F], char (&&second)[S], Rest ... rest) {
    string strFirst  = string( first, F);
    string strSecond = string( second, S);
    cout << "arr, arr, rest" << endl;
    return inListi( strFirst, strSecond, rest...);
}
template<int F, int S, typename ... Rest>
bool inListi( const char (&&first)[F], char (&&second)[S], Rest ... rest) {
    string strFirst  = string( first, F);
    string strSecond = string( second, S);
    cout << "const arr, arr, rest" << endl;
    return inListi( strFirst, strSecond, rest...);
}
template<int F, int S, typename ... Rest>
bool inListi( char (&&first)[F], const char (&&second)[S], Rest ... rest) {
    string strFirst  = string( first, F);
    string strSecond = string( second, S);
    cout << "arr, const arr, rest" << endl;
    return inListi( strFirst, strSecond, rest...);
}
template<int F, int S, typename ... Rest>
bool inListi( const char (&&first)[F], const char (&&second)[S], Rest ... rest) {
    string strFirst = string( first, F);
    string strSecond = string( second, S);
    cout << "const arr, const arr, rest" << endl;
    return inListi( strFirst, strSecond, rest...);
}


int main() {

    if( inListi( "Hello", "World", "HEllo"))
        cout << "Hello is in the listi." << endl;
    else
        cout << "Hello is not in the listi." << endl;

    return 0;
}

The output of the program is the following:

[bitdiot foo]$ g++ forStackOverflow.cpp -std=gnu++0x
[bitdiot foo]$ ./a.out
GENERIC inListi
first is A6_c
second is A6_c
GENERIC inListi
first is A6_c
second is PKc
Hello is not in the listi.

Notice, that none of the intermediary code is called, it goes straight to using the generic version. Also, another thing that looks weird is the 'PKc'. Which I am assuming is type char*. Now, why would it have a different type?

Anyways, thanks!!

解决方案

It looks like you could use an overload for const char* (which is perhaps what the PKc refers to).

Maybe something like:

template<typename ... Rest>
bool inListi(const char *first, const char *second, Rest... rest) {
    cout << "const char*, const char*, rest" << endl;
    return inListi(string(first), string(second), rest...);
} 

Two other things:

  • note the use of temporaries so that we'll call the string&& version
  • a const char* overload will match the first call, but you might need more overloads to handle subsequent calls

Another edit: some great feedback on prevent array decay in parameter pack expansion shows us how this can be done by using rvalue references on the parameter pack:

#include <iostream>
#include <string>
#include <utility>
#include <algorithm>
#include <cctype>

template <typename T>
bool inListi(T&& value)
{
  return false;
}

template <typename FirstType, typename SecondType, typename... Rest>
bool inListi(FirstType&& first, SecondType&& second, Rest&&... rest)
{
  if (first == second)
    return true;
  else
    return inListi(std::forward<FirstType&&>(first), rest...);
}

template <int N, int M, typename... Rest>
bool inListi(char (&first)[N], char (&second)[M], Rest&&... rest)
{
  std::string lFirst(first, N);
  std::transform(lFirst.begin(), lFirst.end(), lFirst.begin(), ::tolower);
  std::string lSecond(second, M);
  std::transform(lSecond.begin(), lSecond.end(), lSecond.begin(), ::tolower);

  if (lFirst == lSecond)
    return true;
  else
    return inListi(first, rest...);
}

template <typename... Rest>
bool inListi(const char *first, const char *second, Rest&&... rest)
{
  std::string lFirst(first);
  std::transform(lFirst.begin(), lFirst.end(), lFirst.begin(), ::tolower);
  std::string lSecond(second);
  std::transform(lSecond.begin(), lSecond.end(), lSecond.begin(), ::tolower);

  if (lFirst == lSecond)
    return true;
  else
    return inListi(first, rest...);
}

int main() {
  char a[5] = {'H','e','l','l','o'};
  char b[5] = {'W','o','r','l','d'};
  char c[5] = {'H','E','l','l','o'};
  std::cout << inListi(a, b, c) << '\n';
  std::cout << inListi("Hello", "World", "HEllo") << '\n';
  std::cout << inListi(5, 42, 5) << '\n';
}

This works as long as all arguments have the same type. If you want to start mixing types, you'll probably need to start writing all of the appropriate pairs of overloads.

这篇关于专门的问题变量模板函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆