std :: sort与本地类型比较

Bas*_*tch 3 c++ gcc

以下示例

// file mysort.cc
#include <string>
#include <vector>
#include <algorithm>
#include <string.h>

void mysort (const char**tab, unsigned size) {
  std::vector<int> vecix;
  vecix.resize(size);
  struct CompareIndex {
    const char**t;
    CompareIndex(const char**p) : t(p) {};
    bool operator() (int l, int r)  {
      return strcmp(t[l], t[r])<0;
    }
  };
  CompareIndex compix(tab);
  for (unsigned ix=0; ix<size; ix++) vecix[ix] = ix;
  std::stable_sort(vecix.begin(), vecix.end(), compix);
  std::vector<const char*> vecstr;
  vecstr.resize(size);
  for (unsigned ix=0; ix<size; ix++) vecstr[ix] = tab[vecix[ix]];
  for (unsigned ix=0; ix<size; ix++) tab[ix] = vecstr[ix];
}    
Run Code Online (Sandbox Code Playgroud)

无法编译(在C++ 03标准中使用Debian/Sid/x86-64上的GCC 4.8.2)

mysort.cc: In function 'void mysort(const char**, unsigned int)':
mysort.cc:19:58: error: no matching function for call to 
      'stable_sort(std::vector<int>::iterator, 
                   std::vector<int>::iterator, 
                   mysort(const char**, unsigned int)::CompareIndex&)'
   std::stable_sort(vecix.begin(), vecix.end(), compix);
                                                      ^


In file included from /usr/include/c++/4.8/algorithm:62:0,
                 from mysort.cc:4:
/usr/include/c++/4.8/bits/stl_algo.h:5682:5: note: 
       template<class _RAIter, class _Compare>
                void std::stable_sort(_RAIter, _RAIter, _Compare)
     stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last,
     ^
/usr/include/c++/4.8/bits/stl_algo.h:5682:5: note:   
    template argument deduction/substitution failed:
mysort.cc: In substitution of 'template<class _RAIter, class _Compare>
     void std::stable_sort(_RAIter, _RAIter, _Compare)
     [with _RAIter = __gnu_cxx::__normal_iterator<int*, std::vector<int> >;
           _Compare = mysort(const char**, unsigned int)::CompareIndex]':
mysort.cc:19:58:   required from here
mysort.cc:19:58: error: template argument for
    'template<class _RAIter, class _Compare> 
         void std::stable_sort(_RAIter, _RAIter, _Compare)'
     uses local type 'mysort(const char**, unsigned int)::CompareIndex'
       std::stable_sort(vecix.begin(), vecix.end(), compix);
                                                          ^
mysort.cc:19:58: error:   trying to instantiate
            'template<class _RAIter, class _Compare>
                     void std::stable_sort(_RAIter, _RAIter, _Compare)'
Run Code Online (Sandbox Code Playgroud)

上述用编译GCC 4.8使用

  g++ -Wall -c mysort.cc
Run Code Online (Sandbox Code Playgroud)

我得到了同样的错误

  g++ -std=c++03 -Wall -c mysort.cc
Run Code Online (Sandbox Code Playgroud)

或者

  g++ -std=c++98 -Wall -c mysort.cc
Run Code Online (Sandbox Code Playgroud)

但没有错误

  g++ -std=c++11 -c mysort.cc
Run Code Online (Sandbox Code Playgroud)

鉴于我g++ -v是一个gcc version 4.8.2 (Debian 4.8.2-12)

但是用Clang/LLVM 3.4编译

  clang++ -Wall -c mysort.cc
Run Code Online (Sandbox Code Playgroud)

我只收到警告:

  mysort.cc:19:7: warning: template argument uses local 
                  type 'CompareIndex'
                [-Wlocal-type-template-args]
  std::stable_sort(vecix.begin(), vecix.end(), compix);
  ^~~
  1 warning generated.
Run Code Online (Sandbox Code Playgroud)

(我还是路过的时候只得到一个警告不是错误-std=c++03或者-std=c++98clang++与但没有任何警告clang++ -std=c++11)

所以我的问题是:为什么GCC的错误和Clang的警告?我的代码是否合法且没有未定义的行为(符合C++ 03标准)?我应该在我的编译单元中CompareIndex创建全局struct吗?

动机

当然,这是一种对C字符串数组进行排序的愚蠢方法.真正的代码有点不同.事实上,我正在尝试使用std::stable_sort我的MELT插件(一种特定于域的语言来扩展和定制GCC).MELT正在生成C++代码并具有复制 垃圾收集器(因此指针由GC移动).因此,我需要使用索引数组进行排序:compare函数实际上调用了一个MELT闭包(它可以在任意时刻触发复制GC),因此我需要按索引排序(而不是按原始指针排序).我想保持MELT生成的C++代码符合编译GCC所需的C++标准(03或98).

变通

感谢juanchopanza的回答,我之前通过移动CompareIndex全球范围的声明解决了这个问题mysort.

我刚刚承诺了海湾合作委员会MELT分会的svn修订版206748; 它的文件gcc/melt/warmelt-base.melt现在包含一个multiple_sort_newMELT函数(multiple_sort当它运行良好时替换它)std::stable_sort,以及Melt_Sort_Compare_Index生成的C++代码中的全局类.

jua*_*nza 5

在C++ 03中不允许使用本地类型作为模板参数.

来自ISO/IEC 14882,14.3.1模板类型参数[temp.arg.type]:

本地类型,没有链接的类型,未命名的类型或从这些类型中的任何类型复合的类型不应该用作模板类型参数的模板参数.

给出的例子如下:

template <typename T> struct Foo {};

void foo()
{
  struct Bar {};
  Foo<Bar> b1;   // error: local type used as template-argument
  Foo<Bar*> x4;  // error: pointer to local type used as template-argument
}
Run Code Online (Sandbox Code Playgroud)

这个限制已在C++ 11中解除.